globally avoid using symbols since we're moving to json storage

Andrew Cantino vor 11 Jahren
Ursprung
Commit
a408ae48ea
36 geänderte Dateien mit 612 neuen Zeilen und 632 gelöschten Zeilen
  1. 2 2
      app/concerns/email_concern.rb
  2. 8 8
      app/concerns/twitter_concern.rb
  3. 6 6
      app/concerns/weibo_concern.rb
  4. 17 3
      app/models/agent.rb
  5. 12 12
      app/models/agents/adioso_agent.rb
  6. 14 14
      app/models/agents/digest_email_agent.rb
  7. 4 4
      app/models/agents/email_agent.rb
  8. 22 22
      app/models/agents/event_formatting_agent.rb
  9. 70 70
      app/models/agents/human_task_agent.rb
  10. 2 2
      app/models/agents/manual_event_agent.rb
  11. 27 27
      app/models/agents/peak_detector_agent.rb
  12. 4 4
      app/models/agents/post_agent.rb
  13. 10 10
      app/models/agents/sentiment_agent.rb
  14. 15 15
      app/models/agents/translation_agent.rb
  15. 24 24
      app/models/agents/trigger_agent.rb
  16. 25 25
      app/models/agents/twilio_agent.rb
  17. 20 20
      app/models/agents/twitter_publish_agent.rb
  18. 23 23
      app/models/agents/twitter_stream_agent.rb
  19. 12 12
      app/models/agents/twitter_user_agent.rb
  20. 2 2
      app/models/agents/user_location_agent.rb
  21. 8 8
      app/models/agents/weather_agent.rb
  22. 39 39
      app/models/agents/website_agent.rb
  23. 19 19
      app/models/agents/weibo_publish_agent.rb
  24. 11 11
      app/models/agents/weibo_user_agent.rb
  25. 7 4
      app/models/event.rb
  26. 9 0
      lib/json_with_indifferent_access.rb
  27. 0 46
      lib/serialize_and_normalize.rb
  28. 1 1
      spec/controllers/agents_controller_spec.rb
  29. 7 7
      spec/fixtures/agents.yml
  30. 2 2
      spec/fixtures/events.yml
  31. 2 2
      spec/models/agent_spec.rb
  32. 5 5
      spec/models/agents/digest_email_agent_spec.rb
  33. 4 4
      spec/models/agents/email_agent_spec.rb
  34. 97 97
      spec/models/agents/human_task_agent_spec.rb
  35. 29 29
      spec/models/agents/peak_detector_agent_spec.rb
  36. 53 53
      spec/models/agents/trigger_agent_spec.rb

+ 2 - 2
app/concerns/email_concern.rb

@@ -8,11 +8,11 @@ module EmailConcern
8 8
   end
9 9
 
10 10
   def validate_email_options
11
-    errors.add(:base, "subject and expected_receive_period_in_days are required") unless options[:subject].present? && options[:expected_receive_period_in_days].present?
11
+    errors.add(:base, "subject and expected_receive_period_in_days are required") unless options['subject'].present? && options['expected_receive_period_in_days'].present?
12 12
   end
13 13
 
14 14
   def working?
15
-    last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
15
+    last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
16 16
   end
17 17
 
18 18
   def present(payload)

+ 8 - 8
app/concerns/twitter_concern.rb

@@ -7,20 +7,20 @@ module TwitterConcern
7 7
   end
8 8
 
9 9
   def validate_twitter_options
10
-    unless options[:consumer_key].present? &&
11
-      options[:consumer_secret].present? &&
12
-      options[:oauth_token].present? &&
13
-      options[:oauth_token_secret].present?
10
+    unless options['consumer_key'].present? &&
11
+      options['consumer_secret'].present? &&
12
+      options['oauth_token'].present? &&
13
+      options['oauth_token_secret'].present?
14 14
       errors.add(:base, "consumer_key, consumer_secret, oauth_token and oauth_token_secret are required to authenticate with the Twitter API")
15 15
     end
16 16
   end
17 17
 
18 18
   def configure_twitter
19 19
     Twitter.configure do |config|
20
-      config.consumer_key = options[:consumer_key]
21
-      config.consumer_secret = options[:consumer_secret]
22
-      config.oauth_token = options[:oauth_token] || options[:access_key]
23
-      config.oauth_token_secret = options[:oauth_token_secret] || options[:access_secret]
20
+      config.consumer_key = options['consumer_key']
21
+      config.consumer_secret = options['consumer_secret']
22
+      config.oauth_token = options['oauth_token'] || options['access_key']
23
+      config.oauth_token_secret = options['oauth_token_secret'] || options['access_secret']
24 24
     end
25 25
   end
26 26
 

+ 6 - 6
app/concerns/weibo_concern.rb

@@ -6,19 +6,19 @@ module WeiboConcern
6 6
   end
7 7
 
8 8
   def validate_weibo_options
9
-    unless options[:app_key].present? &&
10
-        options[:app_secret].present? &&
11
-        options[:access_token].present?
9
+    unless options['app_key'].present? &&
10
+        options['app_secret'].present? &&
11
+        options['access_token'].present?
12 12
         errors.add(:base, "app_key, app_secret and access_token are required")
13 13
     end
14 14
   end
15 15
 
16 16
   def weibo_client
17 17
     unless @weibo_client
18
-      WeiboOAuth2::Config.api_key = options[:app_key] # WEIBO_APP_KEY
19
-      WeiboOAuth2::Config.api_secret = options[:app_secret] # WEIBO_APP_SECRET
18
+      WeiboOAuth2::Config.api_key = options['app_key'] # WEIBO_APP_KEY
19
+      WeiboOAuth2::Config.api_secret = options['app_secret'] # WEIBO_APP_SECRET
20 20
       @weibo_client = WeiboOAuth2::Client.new
21
-      @weibo_client.get_token_from_hash :access_token => options[:access_token]
21
+      @weibo_client.get_token_from_hash :access_token => options['access_token']
22 22
     end
23 23
     @weibo_client
24 24
   end

+ 17 - 3
app/models/agent.rb

@@ -1,14 +1,12 @@
1
-require 'serialize_and_normalize'
1
+require 'json_with_indifferent_access'
2 2
 require 'assignable_types'
3 3
 require 'markdown_class_attributes'
4 4
 require 'utils'
5 5
 
6 6
 class Agent < ActiveRecord::Base
7
-  include SerializeAndNormalize
8 7
   include AssignableTypes
9 8
   include MarkdownClassAttributes
10 9
 
11
-  serialize_and_normalize :options, :memory
12 10
   markdown_class_attributes :description, :event_description
13 11
 
14 12
   load_types_in "Agents"
@@ -18,9 +16,21 @@ class Agent < ActiveRecord::Base
18 16
 
19 17
   attr_accessible :options, :memory, :name, :type, :schedule, :source_ids
20 18
 
19
+  serialize :options, JSONWithIndifferentAccess
20
+  serialize :memory, JSONWithIndifferentAccess
21
+
22
+  def options=(o)
23
+    self[:options] = ActiveSupport::HashWithIndifferentAccess.new(o)
24
+  end
25
+
26
+  def memory=(o)
27
+    self[:memory] = ActiveSupport::HashWithIndifferentAccess.new(o)
28
+  end
29
+
21 30
   validates_presence_of :name, :user
22 31
   validate :sources_are_owned
23 32
   validate :validate_schedule
33
+  validate :validate_options
24 34
 
25 35
   after_initialize :set_default_schedule
26 36
   before_validation :set_default_schedule
@@ -74,6 +84,10 @@ class Agent < ActiveRecord::Base
74 84
     raise "Implement me in your subclass"
75 85
   end
76 86
 
87
+  def validate_options
88
+    # Implement me in your subclass to test for valid options.
89
+  end
90
+
77 91
   def event_created_within(days)
78 92
     event = most_recent_event
79 93
     event && event.created_at > days.to_i.days.ago && event.payload.present? && event

+ 12 - 12
app/models/agents/adioso_agent.rb

@@ -29,18 +29,18 @@ module Agents
29 29
 
30 30
     def default_options
31 31
       {
32
-        :start_date => Date.today.httpdate[0..15],
33
-        :end_date   => Date.today.plus_with_duration(100).httpdate[0..15],
34
-        :from       => "New York",
35
-        :to         => "Chicago",
36
-        :username   => "xx",
37
-        :password   => "xx",
38
-				:expected_update_period_in_days => "1"
32
+        'start_date' => Date.today.httpdate[0..15],
33
+        'end_date'   => Date.today.plus_with_duration(100).httpdate[0..15],
34
+        'from'       => "New York",
35
+        'to'         => "Chicago",
36
+        'username'   => "xx",
37
+        'password'   => "xx",
38
+				'expected_update_period_in_days' => "1"
39 39
       }
40 40
     end
41 41
 
42 42
     def working?
43
-      event_created_within(options[:expected_update_period_in_days]) && !recent_error_logs?
43
+      event_created_within(options['expected_update_period_in_days']) && !recent_error_logs?
44 44
     end
45 45
 
46 46
     def validate_options
@@ -54,9 +54,9 @@ module Agents
54 54
     end
55 55
 
56 56
     def check
57
-      auth_options = {:basic_auth => {:username =>options[:username], :password=>options[:password]}}
58
-      parse_response = HTTParty.get "http://api.adioso.com/v2/search/parse?q=#{URI.encode(options[:from])}+to+#{URI.encode(options[:to])}", auth_options
59
-      fare_request = parse_response["search_url"].gsub /(end=)(\d*)([^\d]*)(\d*)/, "\\1#{date_to_unix_epoch(options[:end_date])}\\3#{date_to_unix_epoch(options[:start_date])}"
57
+      auth_options = {:basic_auth => {:username =>options[:username], :password=>options['password']}}
58
+      parse_response = HTTParty.get "http://api.adioso.com/v2/search/parse?q=#{URI.encode(options['from'])}+to+#{URI.encode(options['to'])}", auth_options
59
+      fare_request = parse_response["search_url"].gsub /(end=)(\d*)([^\d]*)(\d*)/, "\\1#{date_to_unix_epoch(options['end_date'])}\\3#{date_to_unix_epoch(options['start_date'])}"
60 60
       fare = HTTParty.get fare_request, auth_options
61 61
 
62 62
 			if fare["warnings"]
@@ -64,7 +64,7 @@ module Agents
64 64
 			else
65 65
 				event = fare["results"].min {|a,b| a["cost"] <=> b["cost"]}
66 66
 				event["date"]  = Time.at(event["date"]).to_date.httpdate[0..15]
67
-				event["route"] = "#{options[:from]} to #{options[:to]}" 
67
+				event["route"] = "#{options['from']} to #{options['to']}"
68 68
 				create_event :payload => event
69 69
 			end
70 70
     end

+ 14 - 14
app/models/agents/digest_email_agent.rb

@@ -9,7 +9,7 @@ module Agents
9 9
     description <<-MD
10 10
       The DigestEmailAgent collects any Events sent to it and sends them all via email when run.
11 11
       The email will be sent to your account's address and will have a `subject` and an optional `headline` before
12
-      listing the Events.  If the Events' payloads contain a `:message`, that will be highlighted, otherwise everything in
12
+      listing the Events.  If the Events' payloads contain a `message`, that will be highlighted, otherwise everything in
13 13
       their payloads will be shown.
14 14
 
15 15
       Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent.
@@ -17,29 +17,29 @@ module Agents
17 17
 
18 18
     def default_options
19 19
       {
20
-          :subject => "You have some notifications!",
21
-          :headline => "Your notifications:",
22
-          :expected_receive_period_in_days => "2"
20
+          'subject' => "You have some notifications!",
21
+          'headline' => "Your notifications:",
22
+          'expected_receive_period_in_days' => "2"
23 23
       }
24 24
     end
25 25
 
26 26
     def receive(incoming_events)
27 27
       incoming_events.each do |event|
28
-        self.memory[:queue] ||= []
29
-        self.memory[:queue] << event.payload
30
-        self.memory[:events] ||= []
31
-        self.memory[:events] << event.id
28
+        self.memory['queue'] ||= []
29
+        self.memory['queue'] << event.payload
30
+        self.memory['events'] ||= []
31
+        self.memory['events'] << event.id
32 32
       end
33 33
     end
34 34
 
35 35
     def check
36
-      if self.memory[:queue] && self.memory[:queue].length > 0
37
-        ids = self.memory[:events].join(",")
38
-        groups = self.memory[:queue].map { |payload| present(payload) }
36
+      if self.memory['queue'] && self.memory['queue'].length > 0
37
+        ids = self.memory['events'].join(",")
38
+        groups = self.memory['queue'].map { |payload| present(payload) }
39 39
         log "Sending digest mail to #{user.email} with events [#{ids}]"
40
-        SystemMailer.delay.send_message(:to => user.email, :subject => options[:subject], :headline => options[:headline], :groups => groups)
41
-        self.memory[:queue] = []
42
-        self.memory[:events] = []
40
+        SystemMailer.delay.send_message(:to => user.email, :subject => options['subject'], :headline => options['headline'], :groups => groups)
41
+        self.memory['queue'] = []
42
+        self.memory['events'] = []
43 43
       end
44 44
     end
45 45
   end

+ 4 - 4
app/models/agents/email_agent.rb

@@ -16,16 +16,16 @@ module Agents
16 16
 
17 17
     def default_options
18 18
       {
19
-          :subject => "You have a notification!",
20
-          :headline => "Your notification:",
21
-          :expected_receive_period_in_days => "2"
19
+          'subject' => "You have a notification!",
20
+          'headline' => "Your notification:",
21
+          'expected_receive_period_in_days' => "2"
22 22
       }
23 23
     end
24 24
 
25 25
     def receive(incoming_events)
26 26
       incoming_events.each do |event|
27 27
         log "Sending digest mail to #{user.email} with event #{event.id}"
28
-        SystemMailer.delay.send_message(:to => user.email, :subject => options[:subject], :headline => options[:headline], :groups => [present(event.payload)])
28
+        SystemMailer.delay.send_message(:to => user.email, :subject => options['subject'], :headline => options['headline'], :groups => [present(event.payload)])
29 29
       end
30 30
     end
31 31
   end

+ 22 - 22
app/models/agents/event_formatting_agent.rb

@@ -8,20 +8,20 @@ module Agents
8 8
       For example, here is a possible Event:
9 9
 
10 10
           {
11
-            :high => {
12
-              :celsius => "18",
13
-              :fahreinheit => "64"
11
+            "high": {
12
+              "celsius": "18",
13
+              "fahreinheit": "64"
14 14
             },
15
-            :conditions => "Rain showers",
16
-            :data   => "This is some data"
15
+            "conditions": "Rain showers",
16
+            "data": "This is some data"
17 17
           }
18 18
 
19 19
       You may want to send this event to another Agent, for example a Twilio Agent, which expects a `message` key.
20 20
       You can use an Event Formatting Agent's `instructions` setting to do this in the following way:
21 21
 
22
-          instructions: {
23
-            message: "Today's conditions look like <$.conditions> with a high temperature of <$.high.celsius> degrees Celsius.",
24
-            subject: "$.data"
22
+          "instructions": {
23
+            "message": "Today's conditions look like <$.conditions> with a high temperature of <$.high.celsius> degrees Celsius.",
24
+            "subject": "$.data"
25 25
           }
26 26
 
27 27
       JSONPaths must be between < and > . Make sure that you don't use these symbols anywhere else.
@@ -29,8 +29,8 @@ module Agents
29 29
       Events generated by this possible Event Formatting Agent will look like:
30 30
 
31 31
           {
32
-            :message => "Today's conditions look like Rain showers with a high temperature of 18 degrees Celsius.",
33
-            :subject => "This is some data"
32
+            "message": "Today's conditions look like Rain showers with a high temperature of 18 degrees Celsius.",
33
+            "subject": "This is some data"
34 34
           }
35 35
 
36 36
       If you want to retain original contents of events and only add new keys, then set `mode` to `merge`, otherwise set it to `clean`.
@@ -40,25 +40,25 @@ module Agents
40 40
       To CGI escape output (for example when creating a link), prefix with `escape`, like so:
41 41
 
42 42
           {
43
-            :message => "A peak was on Twitter in <$.group_by>.  Search: https://twitter.com/search?q=<escape $.group_by>"
43
+            "message": "A peak was on Twitter in <$.group_by>.  Search: https://twitter.com/search?q=<escape $.group_by>"
44 44
           }
45 45
     MD
46 46
 
47 47
     event_description "User defined"
48 48
 
49 49
     def validate_options
50
-      errors.add(:base, "instructions, mode, skip_agent, and skip_created_at all need to be present.") unless options[:instructions].present? and options[:mode].present? and options[:skip_agent].present? and options[:skip_created_at].present?
50
+      errors.add(:base, "instructions, mode, skip_agent, and skip_created_at all need to be present.") unless options['instructions'].present? and options['mode'].present? and options['skip_agent'].present? and options['skip_created_at'].present?
51 51
     end
52 52
 
53 53
     def default_options
54 54
       {
55
-        :instructions => {
56
-          :message =>  "You received a text <$.text> from <$.fields.from>",
57
-          :some_other_field => "Looks like the weather is going to be <$.fields.weather>"
55
+        'instructions' => {
56
+          'message' =>  "You received a text <$.text> from <$.fields.from>",
57
+          'some_other_field' => "Looks like the weather is going to be <$.fields.weather>"
58 58
         },
59
-        :mode => "clean",
60
-        :skip_agent => "false",
61
-        :skip_created_at => "false"
59
+        'mode' => "clean",
60
+        'skip_agent' => "false",
61
+        'skip_created_at' => "false"
62 62
       }
63 63
     end
64 64
 
@@ -68,10 +68,10 @@ module Agents
68 68
 
69 69
     def receive(incoming_events)
70 70
       incoming_events.each do |event|
71
-        formatted_event = options[:mode].to_s == "merge" ? event.payload : {}
72
-        options[:instructions].each_pair {|key, value| formatted_event[key] = Utils.interpolate_jsonpaths(value, event.payload) }
73
-        formatted_event[:agent] = Agent.find(event.agent_id).type.slice!(8..-1) unless options[:skip_agent].to_s == "true"
74
-        formatted_event[:created_at] = event.created_at unless options[:skip_created_at].to_s == "true"
71
+        formatted_event = options['mode'].to_s == "merge" ? event.payload : {}
72
+        options['instructions'].each_pair {|key, value| formatted_event[key] = Utils.interpolate_jsonpaths(value, event.payload) }
73
+        formatted_event['agent'] = Agent.find(event.agent_id).type.slice!(8..-1) unless options['skip_agent'].to_s == "true"
74
+        formatted_event['created_at'] = event.created_at unless options['skip_created_at'].to_s == "true"
75 75
         create_event :payload => formatted_event
76 76
       end
77 77
     end

+ 70 - 70
app/models/agents/human_task_agent.rb

@@ -74,69 +74,69 @@ module Agents
74 74
     MD
75 75
 
76 76
     def validate_options
77
-      options[:hit] ||= {}
78
-      options[:hit][:questions] ||= []
79
-
80
-      errors.add(:base, "'trigger_on' must be one of 'schedule' or 'event'") unless %w[schedule event].include?(options[:trigger_on])
81
-      errors.add(:base, "'hit.assignments' should specify the number of HIT assignments to create") unless options[:hit][:assignments].present? && options[:hit][:assignments].to_i > 0
82
-      errors.add(:base, "'hit.title' must be provided") unless options[:hit][:title].present?
83
-      errors.add(:base, "'hit.description' must be provided") unless options[:hit][:description].present?
84
-      errors.add(:base, "'hit.questions' must be provided") unless options[:hit][:questions].present? && options[:hit][:questions].length > 0
85
-
86
-      if options[:trigger_on] == "event"
87
-        errors.add(:base, "'expected_receive_period_in_days' is required when 'trigger_on' is set to 'event'") unless options[:expected_receive_period_in_days].present?
88
-      elsif options[:trigger_on] == "schedule"
89
-        errors.add(:base, "'submission_period' must be set to a positive number of hours when 'trigger_on' is set to 'schedule'") unless options[:submission_period].present? && options[:submission_period].to_i > 0
77
+      options['hit'] ||= {}
78
+      options['hit']['questions'] ||= []
79
+
80
+      errors.add(:base, "'trigger_on' must be one of 'schedule' or 'event'") unless %w[schedule event].include?(options['trigger_on'])
81
+      errors.add(:base, "'hit.assignments' should specify the number of HIT assignments to create") unless options['hit']['assignments'].present? && options['hit']['assignments'].to_i > 0
82
+      errors.add(:base, "'hit.title' must be provided") unless options['hit']['title'].present?
83
+      errors.add(:base, "'hit.description' must be provided") unless options['hit']['description'].present?
84
+      errors.add(:base, "'hit.questions' must be provided") unless options['hit']['questions'].present? && options['hit']['questions'].length > 0
85
+
86
+      if options['trigger_on'] == "event"
87
+        errors.add(:base, "'expected_receive_period_in_days' is required when 'trigger_on' is set to 'event'") unless options['expected_receive_period_in_days'].present?
88
+      elsif options['trigger_on'] == "schedule"
89
+        errors.add(:base, "'submission_period' must be set to a positive number of hours when 'trigger_on' is set to 'schedule'") unless options['submission_period'].present? && options['submission_period'].to_i > 0
90 90
       end
91 91
 
92
-      if options[:hit][:questions].any? { |question| [:key, :name, :required, :type, :question].any? {|k| !question[k].present? } }
92
+      if options['hit']['questions'].any? { |question| %w[key name required type question].any? {|k| !question[k].present? } }
93 93
         errors.add(:base, "all questions must set 'key', 'name', 'required', 'type', and 'question'")
94 94
       end
95 95
 
96
-      if options[:hit][:questions].any? { |question| question[:type] == "selection" && (!question[:selections].present? || question[:selections].length == 0 || !question[:selections].all? {|s| s[:key].present? } || !question[:selections].all? { |s| s[:text].present? })}
96
+      if options['hit']['questions'].any? { |question| question['type'] == "selection" && (!question['selections'].present? || question['selections'].length == 0 || !question['selections'].all? {|s| s['key'].present? } || !question['selections'].all? { |s| s['text'].present? })}
97 97
         errors.add(:base, "all questions of type 'selection' must have a selections array with selections that set 'key' and 'name'")
98 98
       end
99 99
 
100
-      if options[:take_majority] == "true" && options[:hit][:questions].any? { |question| question[:type] != "selection" }
100
+      if options['take_majority'] == "true" && options['hit']['questions'].any? { |question| question['type'] != "selection" }
101 101
         errors.add(:base, "all questions must be of type 'selection' to use the 'take_majority' option")
102 102
       end
103 103
     end
104 104
 
105 105
     def default_options
106 106
       {
107
-        :expected_receive_period_in_days => 2,
108
-        :trigger_on => "event",
109
-        :hit =>
107
+        'expected_receive_period_in_days' => 2,
108
+        'trigger_on' => "event",
109
+        'hit' =>
110 110
           {
111
-            :assignments => 1,
112
-            :title => "Sentiment evaluation",
113
-            :description => "Please rate the sentiment of this message: '<$.message>'",
114
-            :reward => 0.05,
115
-            :lifetime_in_seconds => 24 * 60 * 60,
116
-            :questions =>
111
+            'assignments' => 1,
112
+            'title' => "Sentiment evaluation",
113
+            'description' => "Please rate the sentiment of this message: '<$.message>'",
114
+            'reward' => 0.05,
115
+            'lifetime_in_seconds' => 24 * 60 * 60,
116
+            'questions' =>
117 117
               [
118 118
                 {
119
-                  :type => "selection",
120
-                  :key => "sentiment",
121
-                  :name => "Sentiment",
122
-                  :required => "true",
123
-                  :question => "Please select the best sentiment value:",
124
-                  :selections =>
119
+                  'type' => "selection",
120
+                  'key' => "sentiment",
121
+                  'name' => "Sentiment",
122
+                  'required' => "true",
123
+                  'question' => "Please select the best sentiment value:",
124
+                  'selections' =>
125 125
                     [
126
-                      { :key => "happy", :text => "Happy" },
127
-                      { :key => "sad", :text => "Sad" },
128
-                      { :key => "neutral", :text => "Neutral" }
126
+                      { 'key' => "happy", 'text' => "Happy" },
127
+                      { 'key' => "sad", 'text' => "Sad" },
128
+                      { 'key' => "neutral", 'text' => "Neutral" }
129 129
                     ]
130 130
                 },
131 131
                 {
132
-                  :type => "free_text",
133
-                  :key => "feedback",
134
-                  :name => "Have any feedback for us?",
135
-                  :required => "false",
136
-                  :question => "Feedback",
137
-                  :default => "Type here...",
138
-                  :min_length => "2",
139
-                  :max_length => "2000"
132
+                  'type' => "free_text",
133
+                  'key' => "feedback",
134
+                  'name' => "Have any feedback for us?",
135
+                  'required' => "false",
136
+                  'question' => "Feedback",
137
+                  'default' => "Type here...",
138
+                  'min_length' => "2",
139
+                  'max_length' => "2000"
140 140
                 }
141 141
               ]
142 142
           }
@@ -144,20 +144,20 @@ module Agents
144 144
     end
145 145
 
146 146
     def working?
147
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
147
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
148 148
     end
149 149
 
150 150
     def check
151 151
       review_hits
152 152
 
153
-      if options[:trigger_on] == "schedule" && (memory[:last_schedule] || 0) <= Time.now.to_i - options[:submission_period].to_i * 60 * 60
154
-        memory[:last_schedule] = Time.now.to_i
153
+      if options['trigger_on'] == "schedule" && (memory['last_schedule'] || 0) <= Time.now.to_i - options['submission_period'].to_i * 60 * 60
154
+        memory['last_schedule'] = Time.now.to_i
155 155
         create_hit
156 156
       end
157 157
     end
158 158
 
159 159
     def receive(incoming_events)
160
-      if options[:trigger_on] == "event"
160
+      if options['trigger_on'] == "event"
161 161
         incoming_events.each do |event|
162 162
           create_hit event
163 163
         end
@@ -168,7 +168,7 @@ module Agents
168 168
 
169 169
     def review_hits
170 170
       reviewable_hit_ids = RTurk::GetReviewableHITs.create.hit_ids
171
-      my_reviewed_hit_ids = reviewable_hit_ids & (memory[:hits] || {}).keys.map(&:to_s)
171
+      my_reviewed_hit_ids = reviewable_hit_ids & (memory['hits'] || {}).keys
172 172
       if reviewable_hit_ids.length > 0
173 173
         log "MTurk reports #{reviewable_hit_ids.length} HITs, of which I own [#{my_reviewed_hit_ids.to_sentence}]"
174 174
       end
@@ -178,26 +178,26 @@ module Agents
178 178
 
179 179
         log "Looking at HIT #{hit_id}.  I found #{assignments.length} assignments#{" with the statuses: #{assignments.map(&:status).to_sentence}" if assignments.length > 0}"
180 180
         if assignments.length == hit.max_assignments && assignments.all? { |assignment| assignment.status == "Submitted" }
181
-          payload = { :answers => assignments.map(&:answers) }
181
+          payload = { 'answers' => assignments.map(&:answers) }
182 182
 
183
-          if options[:take_majority] == "true"
183
+          if options['take_majority'] == "true"
184 184
             counts = {}
185
-            options[:hit][:questions].each do |question|
186
-              question_counts = question[:selections].inject({}) { |memo, selection| memo[selection[:key]] = 0; memo }
185
+            options['hit']['questions'].each do |question|
186
+              question_counts = question['selections'].inject({}) { |memo, selection| memo[selection['key']] = 0; memo }
187 187
               assignments.each do |assignment|
188 188
                 answers = ActiveSupport::HashWithIndifferentAccess.new(assignment.answers)
189
-                answer = answers[question[:key]]
189
+                answer = answers[question['key']]
190 190
                 question_counts[answer] += 1
191 191
               end
192
-              counts[question[:key]] = question_counts
192
+              counts[question['key']] = question_counts
193 193
             end
194
-            payload[:counts] = counts
194
+            payload['counts'] = counts
195 195
 
196 196
             majority_answer = counts.inject({}) do |memo, (key, question_counts)|
197 197
               memo[key] = question_counts.to_a.sort {|a, b| a.last <=> b.last }.last.first
198 198
               memo
199 199
             end
200
-            payload[:majority_answer] = majority_answer
200
+            payload['majority_answer'] = majority_answer
201 201
 
202 202
             if all_questions_are_numeric?
203 203
               average_answer = counts.inject({}) do |memo, (key, question_counts)|
@@ -209,44 +209,44 @@ module Agents
209 209
                 memo[key] = sum / divisor.to_f
210 210
                 memo
211 211
               end
212
-              payload[:average_answer] = average_answer
212
+              payload['average_answer'] = average_answer
213 213
             end
214 214
           end
215 215
 
216 216
           event = create_event :payload => payload
217
-          log "Event emitted with answer(s)", :outbound_event => event, :inbound_event => Event.find_by_id(memory[:hits][hit_id])
217
+          log "Event emitted with answer(s)", :outbound_event => event, :inbound_event => Event.find_by_id(memory['hits'][hit_id])
218 218
 
219 219
           assignments.each(&:approve!)
220 220
           hit.dispose!
221 221
 
222
-          memory[:hits].delete(hit_id)
222
+          memory['hits'].delete(hit_id)
223 223
         end
224 224
       end
225 225
     end
226 226
 
227 227
     def all_questions_are_numeric?
228
-      options[:hit][:questions].all? do |question|
229
-        question[:selections].all? do |selection|
230
-          selection[:key] == selection[:key].to_f.to_s || selection[:key] == selection[:key].to_i.to_s
228
+      options['hit']['questions'].all? do |question|
229
+        question['selections'].all? do |selection|
230
+          selection['key'] == selection['key'].to_f.to_s || selection['key'] == selection['key'].to_i.to_s
231 231
         end
232 232
       end
233 233
     end
234 234
 
235 235
     def create_hit(event = nil)
236 236
       payload = event ? event.payload : {}
237
-      title = Utils.interpolate_jsonpaths(options[:hit][:title], payload).strip
238
-      description = Utils.interpolate_jsonpaths(options[:hit][:description], payload).strip
239
-      questions = Utils.recursively_interpolate_jsonpaths(options[:hit][:questions], payload)
237
+      title = Utils.interpolate_jsonpaths(options['hit']['title'], payload).strip
238
+      description = Utils.interpolate_jsonpaths(options['hit']['description'], payload).strip
239
+      questions = Utils.recursively_interpolate_jsonpaths(options['hit']['questions'], payload)
240 240
       hit = RTurk::Hit.create(:title => title) do |hit|
241
-        hit.max_assignments = (options[:hit][:assignments] || 1).to_i
241
+        hit.max_assignments = (options['hit']['assignments'] || 1).to_i
242 242
         hit.description = description
243
-        hit.lifetime = (options[:hit][:lifetime_in_seconds] || 24 * 60 * 60).to_i
243
+        hit.lifetime = (options['hit']['lifetime_in_seconds'] || 24 * 60 * 60).to_i
244 244
         hit.question_form AgentQuestionForm.new(:title => title, :description => description, :questions => questions)
245
-        hit.reward = (options[:hit][:reward] || 0.05).to_f
245
+        hit.reward = (options['hit']['reward'] || 0.05).to_f
246 246
         #hit.qualifications.add :approval_rate, { :gt => 80 }
247 247
       end
248
-      memory[:hits] ||= {}
249
-      memory[:hits][hit.id] = event && event.id
248
+      memory['hits'] ||= {}
249
+      memory['hits'][hit.id] = event && event.id
250 250
       log "HIT created with ID #{hit.id} and URL #{hit.url}", :inbound_event => event
251 251
     end
252 252
 
@@ -314,7 +314,7 @@ module Agents
314 314
                     end
315 315
                   end
316 316
 
317
-                  if question[:default].present?
317
+                  if question['default'].present?
318 318
                     DefaultText do
319 319
                       text question['default']
320 320
                     end

+ 2 - 2
app/models/agents/manual_event_agent.rb

@@ -14,8 +14,8 @@ module Agents
14 14
     end
15 15
 
16 16
     def handle_details_post(params)
17
-      if params[:payload]
18
-        create_event(:payload => params[:payload])
17
+      if params['payload']
18
+        create_event(:payload => params['payload'])
19 19
         { :success => true }
20 20
       else
21 21
         { :success => false, :error => "You must provide a JSON payload" }

+ 27 - 27
app/models/agents/peak_detector_agent.rb

@@ -28,22 +28,22 @@ module Agents
28 28
     MD
29 29
 
30 30
     def validate_options
31
-      unless options[:expected_receive_period_in_days].present? && options[:message].present? && options[:value_path].present?
31
+      unless options['expected_receive_period_in_days'].present? && options['message'].present? && options['value_path'].present?
32 32
         errors.add(:base, "expected_receive_period_in_days, value_path, and message are required")
33 33
       end
34 34
     end
35 35
 
36 36
     def default_options
37 37
       {
38
-          :expected_receive_period_in_days => "2",
39
-          :group_by_path => "filter",
40
-          :value_path => "count",
41
-          :message => "A peak was found"
38
+        'expected_receive_period_in_days' => "2",
39
+        'group_by_path' => "filter",
40
+        'value_path' => "count",
41
+        'message' => "A peak was found"
42 42
       }
43 43
     end
44 44
 
45 45
     def working?
46
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
46
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
47 47
     end
48 48
 
49 49
     def receive(incoming_events)
@@ -57,25 +57,25 @@ module Agents
57 57
     private
58 58
 
59 59
     def check_for_peak(group, event)
60
-      memory[:peaks] ||= {}
61
-      memory[:peaks][group] ||= []
60
+      memory['peaks'] ||= {}
61
+      memory['peaks'][group] ||= []
62 62
 
63
-      if memory[:data][group].length > 4 && (memory[:peaks][group].empty? || memory[:peaks][group].last < event.created_at.to_i - peak_spacing)
63
+      if memory['data'][group].length > 4 && (memory['peaks'][group].empty? || memory['peaks'][group].last < event.created_at.to_i - peak_spacing)
64 64
         average_value, standard_deviation = stats_for(group, :skip_last => 1)
65
-        newest_value, newest_time = memory[:data][group][-1].map(&:to_f)
65
+        newest_value, newest_time = memory['data'][group][-1].map(&:to_f)
66 66
 
67 67
         #p [newest_value, average_value, average_value + std_multiple * standard_deviation, standard_deviation]
68 68
 
69 69
         if newest_value > average_value + std_multiple * standard_deviation
70
-          memory[:peaks][group] << newest_time
71
-          memory[:peaks][group].reject! { |p| p <= newest_time - window_duration }
72
-          create_event :payload => {:message => options[:message], :peak => newest_value, :peak_time => newest_time, :grouped_by => group.to_s}
70
+          memory['peaks'][group] << newest_time
71
+          memory['peaks'][group].reject! { |p| p <= newest_time - window_duration }
72
+          create_event :payload => { 'message' => options['message'], 'peak' => newest_value, 'peak_time' => newest_time, 'grouped_by' => group.to_s }
73 73
         end
74 74
       end
75 75
     end
76 76
 
77 77
     def stats_for(group, options = {})
78
-      data = memory[:data][group].map { |d| d.first.to_f }
78
+      data = memory['data'][group].map { |d| d.first.to_f }
79 79
       data = data[0...(data.length - (options[:skip_last] || 0))]
80 80
       length = data.length.to_f
81 81
       mean = 0
@@ -94,39 +94,39 @@ module Agents
94 94
     end
95 95
 
96 96
     def window_duration
97
-      if options[:window_duration].present? # The older option
98
-        options[:window_duration].to_i
97
+      if options['window_duration'].present? # The older option
98
+        options['window_duration'].to_i
99 99
       else
100
-        (options[:window_duration_in_days] || 14).to_f.days
100
+        (options['window_duration_in_days'] || 14).to_f.days
101 101
       end
102 102
     end
103 103
 
104 104
     def std_multiple
105
-      (options[:std_multiple] || 3).to_f
105
+      (options['std_multiple'] || 3).to_f
106 106
     end
107 107
 
108 108
     def peak_spacing
109
-      if options[:peak_spacing].present? # The older option
110
-        options[:peak_spacing].to_i
109
+      if options['peak_spacing'].present? # The older option
110
+        options['peak_spacing'].to_i
111 111
       else
112
-        (options[:min_peak_spacing_in_days] || 2).to_f.days
112
+        (options['min_peak_spacing_in_days'] || 2).to_f.days
113 113
       end
114 114
     end
115 115
 
116 116
     def group_for(event)
117
-      ((options[:group_by_path].present? && Utils.value_at(event.payload, options[:group_by_path])) || 'no_group')
117
+      ((options['group_by_path'].present? && Utils.value_at(event.payload, options['group_by_path'])) || 'no_group')
118 118
     end
119 119
 
120 120
     def remember(group, event)
121
-      memory[:data] ||= {}
122
-      memory[:data][group] ||= []
123
-      memory[:data][group] << [Utils.value_at(event.payload, options[:value_path]), event.created_at.to_i]
121
+      memory['data'] ||= {}
122
+      memory['data'][group] ||= []
123
+      memory['data'][group] << [ Utils.value_at(event.payload, options['value_path']), event.created_at.to_i ]
124 124
       cleanup group
125 125
     end
126 126
 
127 127
     def cleanup(group)
128
-      newest_time = memory[:data][group].last.last
129
-      memory[:data][group].reject! { |value, time| time <= newest_time - window_duration }
128
+      newest_time = memory['data'][group].last.last
129
+      memory['data'][group].reject! { |value, time| time <= newest_time - window_duration }
130 130
     end
131 131
   end
132 132
 end

+ 4 - 4
app/models/agents/post_agent.rb

@@ -11,17 +11,17 @@ module Agents
11 11
 
12 12
     def default_options
13 13
       {
14
-        :post_url => "http://www.example.com",
15
-        :expected_receive_period_in_days => 1
14
+        'post_url' => "http://www.example.com",
15
+        'expected_receive_period_in_days' => 1
16 16
       }
17 17
     end
18 18
 
19 19
     def working?
20
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
20
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
21 21
     end
22 22
 
23 23
     def validate_options
24
-      unless options[:post_url].present? && options[:expected_receive_period_in_days].present?
24
+      unless options['post_url'].present? && options['expected_receive_period_in_days'].present?
25 25
         errors.add(:base, "post_url and expected_receive_period_in_days are required fields")
26 26
       end
27 27
     end

+ 10 - 10
app/models/agents/sentiment_agent.rb

@@ -28,31 +28,31 @@ module Agents
28 28
 
29 29
     def default_options
30 30
       {
31
-        :content => "$.message.text[*]",
32
-        :expected_receive_period_in_days => 1
31
+        'content' => "$.message.text[*]",
32
+        'expected_receive_period_in_days' => 1
33 33
       }
34 34
     end
35 35
 
36 36
     def working?
37
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
37
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
38 38
     end
39 39
 
40 40
     def receive(incoming_events)
41 41
       anew = self.class.sentiment_hash
42 42
       incoming_events.each do |event|
43
-        Utils.values_at(event.payload, options[:content]).each do |content|
43
+        Utils.values_at(event.payload, options['content']).each do |content|
44 44
           sent_values = sentiment_values anew, content
45
-          create_event :payload => { :content => content,
46
-                                     :valence => sent_values[0],
47
-                                     :arousal => sent_values[1],
48
-                                     :dominance => sent_values[2],
49
-                                     :original_event => event.payload }
45
+          create_event :payload => { 'content' => content,
46
+                                     'valence' => sent_values[0],
47
+                                     'arousal' => sent_values[1],
48
+                                     'dominance' => sent_values[2],
49
+                                     'original_event' => event.payload }
50 50
         end
51 51
       end
52 52
     end
53 53
 
54 54
     def validate_options
55
-      errors.add(:base, "content and expected_receive_period_in_days must be present") unless options[:content].present? && options[:expected_receive_period_in_days].present?
55
+      errors.add(:base, "content and expected_receive_period_in_days must be present") unless options['content'].present? && options['expected_receive_period_in_days'].present?
56 56
     end
57 57
 
58 58
     def self.sentiment_hash

+ 15 - 15
app/models/agents/translation_agent.rb

@@ -17,26 +17,26 @@ module Agents
17 17
 
18 18
     def default_options
19 19
       {
20
-        :client_id => "xxxxxx",
21
-        :client_secret => "xxxxxx",
22
-        :to => "fi",
23
-        :expected_receive_period_in_days => 1,
24
-        :content => {
25
-          :text => "$.message.text",
26
-          :content => "$.xyz"
20
+        'client_id' => "xxxxxx",
21
+        'client_secret' => "xxxxxx",
22
+        'to' => "fi",
23
+        'expected_receive_period_in_days' => 1,
24
+        'content' => {
25
+          'text' => "$.message.text",
26
+          'content' => "$.xyz"
27 27
         }
28 28
       }
29 29
     end
30 30
 
31 31
     def working?
32
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
32
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
33 33
     end
34 34
 
35 35
     def translate(text, to, access_token)
36 36
       translate_uri = URI 'http://api.microsofttranslator.com/v2/Ajax.svc/Translate'
37 37
       params = {
38
-          :text => text,
39
-          :to => to
38
+        'text' => text,
39
+        'to' => to
40 40
       }
41 41
       translate_uri.query = URI.encode_www_form params
42 42
       request = Net::HTTP::Get.new translate_uri.request_uri
@@ -47,7 +47,7 @@ module Agents
47 47
     end
48 48
 
49 49
     def validate_options
50
-      unless options[:client_id].present? && options[:client_secret].present? && options[:to].present? && options[:content].present? && options[:expected_receive_period_in_days].present?
50
+      unless options['client_id'].present? && options['client_secret'].present? && options['to'].present? && options['content'].present? && options['expected_receive_period_in_days'].present?
51 51
         errors.add :base, "client_id,client_secret,to,expected_receive_period_in_days and content are all required"
52 52
       end
53 53
     end
@@ -60,16 +60,16 @@ module Agents
60 60
 
61 61
     def receive(incoming_events)
62 62
       auth_uri = URI "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13"
63
-      response = postform auth_uri, :client_id => options[:client_id],
64
-                                    :client_secret => options[:client_secret],
63
+      response = postform auth_uri, :client_id => options['client_id'],
64
+                                    :client_secret => options['client_secret'],
65 65
                                     :scope => "http://api.microsofttranslator.com",
66 66
                                     :grant_type => "client_credentials"
67 67
       access_token = JSON.parse(response.body)["access_token"]
68 68
       incoming_events.each do |event|
69 69
         translated_event = {}
70
-        options[:content].each_pair do |key, value|
70
+        options['content'].each_pair do |key, value|
71 71
           to_be_translated = Utils.values_at event.payload, value
72
-          translated_event[key] = translate to_be_translated.first, options[:to], access_token
72
+          translated_event[key] = translate to_be_translated.first, options['to'], access_token
73 73
         end
74 74
         create_event :payload => translated_event
75 75
       end

+ 24 - 24
app/models/agents/trigger_agent.rb

@@ -23,57 +23,57 @@ module Agents
23 23
     MD
24 24
 
25 25
     def validate_options
26
-      unless options[:expected_receive_period_in_days].present? && options[:message].present? && options[:rules].present? &&
27
-          options[:rules].all? { |rule| rule[:type].present? && VALID_COMPARISON_TYPES.include?(rule[:type]) && rule[:value].present? && rule[:path].present? }
26
+      unless options['expected_receive_period_in_days'].present? && options['message'].present? && options['rules'].present? &&
27
+          options['rules'].all? { |rule| rule['type'].present? && VALID_COMPARISON_TYPES.include?(rule['type']) && rule['value'].present? && rule['path'].present? }
28 28
         errors.add(:base, "expected_receive_period_in_days, message, and rules, with a type, value, and path for every rule, are required")
29 29
       end
30 30
     end
31 31
 
32 32
     def default_options
33 33
       {
34
-          :expected_receive_period_in_days => "2",
35
-          :rules => [{
36
-                         :type => "regex",
37
-                         :value => "foo\\d+bar",
38
-                         :path => "topkey.subkey.subkey.goal",
39
-                     }],
40
-          :message => "Looks like your pattern matched in '<value>'!"
34
+        'expected_receive_period_in_days' => "2",
35
+        'rules' => [{
36
+                      'type' => "regex",
37
+                      'value' => "foo\\d+bar",
38
+                      'path' => "topkey.subkey.subkey.goal",
39
+                    }],
40
+        'message' => "Looks like your pattern matched in '<value>'!"
41 41
       }
42 42
     end
43 43
 
44 44
     def working?
45
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
45
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
46 46
     end
47 47
 
48 48
     def receive(incoming_events)
49 49
       incoming_events.each do |event|
50
-        match = options[:rules].all? do |rule|
51
-          value_at_path = Utils.value_at(event[:payload], rule[:path])
52
-          case rule[:type]
50
+        match = options['rules'].all? do |rule|
51
+          value_at_path = Utils.value_at(event['payload'], rule['path'])
52
+          case rule['type']
53 53
             when "regex"
54
-              value_at_path.to_s =~ Regexp.new(rule[:value], Regexp::IGNORECASE)
54
+              value_at_path.to_s =~ Regexp.new(rule['value'], Regexp::IGNORECASE)
55 55
             when "!regex"
56
-              value_at_path.to_s !~ Regexp.new(rule[:value], Regexp::IGNORECASE)
56
+              value_at_path.to_s !~ Regexp.new(rule['value'], Regexp::IGNORECASE)
57 57
             when "field>value"
58
-              value_at_path.to_f > rule[:value].to_f
58
+              value_at_path.to_f > rule['value'].to_f
59 59
             when "field>=value"
60
-              value_at_path.to_f >= rule[:value].to_f
60
+              value_at_path.to_f >= rule['value'].to_f
61 61
             when "field<value"
62
-              value_at_path.to_f < rule[:value].to_f
62
+              value_at_path.to_f < rule['value'].to_f
63 63
             when "field<=value"
64
-              value_at_path.to_f <= rule[:value].to_f
64
+              value_at_path.to_f <= rule['value'].to_f
65 65
             when "field==value"
66
-              value_at_path.to_s == rule[:value].to_s
66
+              value_at_path.to_s == rule['value'].to_s
67 67
             when "field!=value"
68
-              value_at_path.to_s != rule[:value].to_s
68
+              value_at_path.to_s != rule['value'].to_s
69 69
             else
70
-              raise "Invalid :type of #{rule[:type]} in TriggerAgent##{id}"
70
+              raise "Invalid type of #{rule['type']} in TriggerAgent##{id}"
71 71
           end
72 72
         end
73 73
 
74 74
         if match
75
-          create_event :payload => { :message => make_message(event[:payload]) } # Maybe this should include the
76
-                                                                                 # original event as well?
75
+          create_event :payload => { 'message' => make_message(event[:payload]) } # Maybe this should include the
76
+                                                                                  # original event as well?
77 77
         end
78 78
       end
79 79
     end

+ 25 - 25
app/models/agents/twilio_agent.rb

@@ -9,7 +9,7 @@ module Agents
9 9
     description <<-MD
10 10
       The TwilioAgent receives and collects events and sends them via text message or gives you a call when scheduled.
11 11
 
12
-      It is assumed that events have a `:message`, `:text`, or `:sms` key, the value of which is sent as the content of the text message/call. You can use Event Formatting Agent if your event does not provide these keys.
12
+      It is assumed that events have a `message`, `text`, or `sms` key, the value of which is sent as the content of the text message/call. You can use Event Formatting Agent if your event does not provide these keys.
13 13
 
14 14
       Set `receiver_cell` to the number to receive text messages/call and `sender_cell` to the number sending them.
15 15
 
@@ -22,35 +22,35 @@ module Agents
22 22
 
23 23
     def default_options
24 24
       {
25
-        :account_sid => 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
26
-        :auth_token => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
27
-        :sender_cell => 'xxxxxxxxxx',
28
-        :receiver_cell => 'xxxxxxxxxx',
29
-        :server_url    => 'http://somename.com:3000',
30
-        :receive_text  => 'true',
31
-        :receive_call  => 'false',
32
-        :expected_receive_period_in_days => '1'
25
+        'account_sid' => 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
26
+        'auth_token' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
27
+        'sender_cell' => 'xxxxxxxxxx',
28
+        'receiver_cell' => 'xxxxxxxxxx',
29
+        'server_url'    => 'http://somename.com:3000',
30
+        'receive_text'  => 'true',
31
+        'receive_call'  => 'false',
32
+        'expected_receive_period_in_days' => '1'
33 33
       }
34 34
     end
35 35
 
36 36
     def validate_options
37
-      unless options[:account_sid].present? && options[:auth_token].present? && options[:sender_cell].present? && options[:receiver_cell].present? && options[:expected_receive_period_in_days].present? && options[:receive_call].present? && options[:receive_text].present?
37
+      unless options['account_sid'].present? && options['auth_token'].present? && options['sender_cell'].present? && options['receiver_cell'].present? && options['expected_receive_period_in_days'].present? && options['receive_call'].present? && options['receive_text'].present?
38 38
         errors.add(:base, 'account_sid, auth_token, sender_cell, receiver_cell, receive_text, receive_call and expected_receive_period_in_days are all required')
39 39
       end
40 40
     end
41 41
 
42 42
     def receive(incoming_events)
43
-      @client = Twilio::REST::Client.new options[:account_sid], options[:auth_token]
44
-      memory[:pending_calls] ||= {}
43
+      @client = Twilio::REST::Client.new options['account_sid'], options['auth_token']
44
+      memory['pending_calls'] ||= {}
45 45
       incoming_events.each do |event|
46
-        message = (event.payload[:message] || event.payload[:text] || event.payload[:sms]).to_s
46
+        message = (event.payload['message'] || event.payload['text'] || event.payload['sms']).to_s
47 47
         if message != ""
48
-          if options[:receive_call].to_s == 'true'
48
+          if options['receive_call'].to_s == 'true'
49 49
             secret = SecureRandom.hex 3
50
-            memory[:pending_calls][secret] = message
50
+            memory['pending_calls'][secret] = message
51 51
             make_call secret
52 52
           end
53
-          if options[:receive_text].to_s == 'true'
53
+          if options['receive_text'].to_s == 'true'
54 54
             message = message.slice 0..160
55 55
             send_message message
56 56
           end
@@ -59,19 +59,19 @@ module Agents
59 59
     end
60 60
 
61 61
     def working?
62
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
62
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
63 63
     end
64 64
 
65 65
     def send_message(message)
66
-      @client.account.sms.messages.create :from => options[:sender_cell],
67
-                                          :to => options[:receiver_cell],
66
+      @client.account.sms.messages.create :from => options['sender_cell'],
67
+                                          :to => options['receiver_cell'],
68 68
                                           :body => message
69 69
     end
70 70
 
71 71
     def make_call(secret)
72
-      @client.account.calls.create :from => options[:sender_cell],
73
-                                   :to => options[:receiver_cell],
74
-                                   :url => post_url(options[:server_url],secret)
72
+      @client.account.calls.create :from => options['sender_cell'],
73
+                                   :to => options['receiver_cell'],
74
+                                   :url => post_url(options['server_url'],secret)
75 75
     end
76 76
 
77 77
     def post_url(server_url,secret)
@@ -79,9 +79,9 @@ module Agents
79 79
     end
80 80
 
81 81
     def receive_webhook(params)
82
-      if memory[:pending_calls].has_key? params[:secret]
83
-        response = Twilio::TwiML::Response.new {|r| r.Say memory[:pending_calls][params[:secret]], :voice => 'woman'}
84
-        memory[:pending_calls].delete params[:secret]
82
+      if memory['pending_calls'].has_key? params['secret']
83
+        response = Twilio::TwiML::Response.new {|r| r.Say memory['pending_calls'][params['secret']], :voice => 'woman'}
84
+        memory['pending_calls'].delete params['secret']
85 85
         [response.text, 200]
86 86
       end
87 87
     end

+ 20 - 20
app/models/agents/twitter_publish_agent.rb

@@ -19,25 +19,25 @@ module Agents
19 19
     MD
20 20
 
21 21
     def validate_options
22
-      unless options[:username].present? &&
23
-        options[:expected_update_period_in_days].present?
22
+      unless options['username'].present? &&
23
+        options['expected_update_period_in_days'].present?
24 24
         errors.add(:base, "username and expected_update_period_in_days are required")
25 25
       end      
26 26
     end
27 27
 
28 28
     def working?
29
-      (event = event_created_within(options[:expected_update_period_in_days])) && event.payload[:success] == true && !recent_error_logs?
29
+      (event = event_created_within(options['expected_update_period_in_days'])) && event.payload['success'] == true && !recent_error_logs?
30 30
     end
31 31
 
32 32
     def default_options
33 33
       {
34
-          :username => "",
35
-          :expected_update_period_in_days => "10",
36
-          :consumer_key => "---",
37
-          :consumer_secret => "---",
38
-          :oauth_token => "---",
39
-          :oauth_token_secret => "---",
40
-          :message_path => "text"
34
+        'username' => "",
35
+        'expected_update_period_in_days' => "10",
36
+        'consumer_key' => "---",
37
+        'consumer_secret' => "---",
38
+        'oauth_token' => "---",
39
+        'oauth_token_secret' => "---",
40
+        'message_path' => "text"
41 41
       }
42 42
     end
43 43
 
@@ -47,22 +47,22 @@ module Agents
47 47
         incoming_events = incoming_events.first(20)
48 48
       end
49 49
       incoming_events.each do |event|
50
-        tweet_text = Utils.value_at(event.payload, options[:message_path])
50
+        tweet_text = Utils.value_at(event.payload, options['message_path'])
51 51
         begin
52 52
           publish_tweet tweet_text
53 53
           create_event :payload => {
54
-            :success => true,
55
-            :published_tweet => tweet_text,
56
-            :agent_id => event.agent_id,
57
-            :event_id => event.id
54
+            'success' => true,
55
+            'published_tweet' => tweet_text,
56
+            'agent_id' => event.agent_id,
57
+            'event_id' => event.id
58 58
           }
59 59
         rescue Twitter::Error => e
60 60
           create_event :payload => {
61
-            :success => false,
62
-            :error => e.message,
63
-            :failed_tweet => tweet_text,
64
-            :agent_id => event.agent_id,
65
-            :event_id => event.id
61
+            'success' => false,
62
+            'error' => e.message,
63
+            'failed_tweet' => tweet_text,
64
+            'agent_id' => event.agent_id,
65
+            'event_id' => event.id
66 66
           }
67 67
         end
68 68
       end

+ 23 - 23
app/models/agents/twitter_stream_agent.rb

@@ -54,26 +54,26 @@ module Agents
54 54
     default_schedule "11pm"
55 55
 
56 56
     def validate_options
57
-      unless options[:filters].present? &&
58
-             options[:expected_update_period_in_days].present? &&
59
-             options[:generate].present?
57
+      unless options['filters'].present? &&
58
+             options['expected_update_period_in_days'].present? &&
59
+             options['generate'].present?
60 60
         errors.add(:base, "expected_update_period_in_days, generate, and filters are required fields")
61 61
       end
62 62
     end
63 63
 
64 64
     def working?
65
-      event_created_within(options[:expected_update_period_in_days]) && !recent_error_logs?
65
+      event_created_within(options['expected_update_period_in_days']) && !recent_error_logs?
66 66
     end
67 67
 
68 68
     def default_options
69 69
       {
70
-          :consumer_key => "---",
71
-          :consumer_secret => "---",
72
-          :oauth_token => "---",
73
-          :oauth_token_secret => "---",
74
-          :filters => %w[keyword1 keyword2],
75
-          :expected_update_period_in_days => "2",
76
-          :generate => "events"
70
+          'consumer_key' => "---",
71
+          'consumer_secret' => "---",
72
+          'oauth_token' => "---",
73
+          'oauth_token_secret' => "---",
74
+          'filters' => %w[keyword1 keyword2],
75
+          'expected_update_period_in_days' => "2",
76
+          'generate' => "events"
77 77
       }
78 78
     end
79 79
 
@@ -81,33 +81,33 @@ module Agents
81 81
       filter = lookup_filter(filter)
82 82
 
83 83
       if filter
84
-        if options[:generate] == "counts"
84
+        if options['generate'] == "counts"
85 85
           # Avoid memory pollution by reloading the Agent.
86 86
           agent = Agent.find(id)
87
-          agent.memory[:filter_counts] ||= {}
88
-          agent.memory[:filter_counts][filter] ||= 0
89
-          agent.memory[:filter_counts][filter] += 1
90
-          remove_unused_keys!(agent, :filter_counts)
87
+          agent.memory['filter_counts'] ||= {}
88
+          agent.memory['filter_counts'][filter] ||= 0
89
+          agent.memory['filter_counts'][filter] += 1
90
+          remove_unused_keys!(agent, 'filter_counts')
91 91
           agent.save!
92 92
         else
93
-          create_event :payload => status.merge(:filter => filter)
93
+          create_event :payload => status.merge('filter' => filter)
94 94
         end
95 95
       end
96 96
     end
97 97
 
98 98
     def check
99
-      if options[:generate] == "counts" && memory[:filter_counts] && memory[:filter_counts].length > 0
100
-        memory[:filter_counts].each do |filter, count|
101
-          create_event :payload => { :filter => filter, :count => count, :time => Time.now.to_i }
99
+      if options['generate'] == "counts" && memory['filter_counts'] && memory['filter_counts'].length > 0
100
+        memory['filter_counts'].each do |filter, count|
101
+          create_event :payload => { 'filter' => filter, 'count' => count, 'time' => Time.now.to_i }
102 102
         end
103 103
       end
104
-      memory[:filter_counts] = {}
104
+      memory['filter_counts'] = {}
105 105
     end
106 106
 
107 107
     protected
108 108
 
109 109
     def lookup_filter(filter)
110
-      options[:filters].each do |known_filter|
110
+      options['filters'].each do |known_filter|
111 111
         if known_filter == filter
112 112
           return filter
113 113
         elsif known_filter.is_a?(Array)
@@ -120,7 +120,7 @@ module Agents
120 120
 
121 121
     def remove_unused_keys!(agent, base)
122 122
       if agent.memory[base]
123
-        (agent.memory[base].keys - agent.options[:filters].map {|f| f.is_a?(Array) ? f.first.to_s : f.to_s }).each do |removed_key|
123
+        (agent.memory[base].keys - agent.options['filters'].map {|f| f.is_a?(Array) ? f.first.to_s : f.to_s }).each do |removed_key|
124 124
           agent.memory[base].delete(removed_key)
125 125
         end
126 126
       end

+ 12 - 12
app/models/agents/twitter_user_agent.rb

@@ -41,36 +41,36 @@ module Agents
41 41
     default_schedule "every_1h"
42 42
 
43 43
     def validate_options
44
-      unless options[:username].present? &&
45
-        options[:expected_update_period_in_days].present?
44
+      unless options['username'].present? &&
45
+        options['expected_update_period_in_days'].present?
46 46
         errors.add(:base, "username and expected_update_period_in_days are required")
47 47
       end      
48 48
     end
49 49
 
50 50
     def working?
51
-      event_created_within(options[:expected_update_period_in_days]) && !recent_error_logs?
51
+      event_created_within(options['expected_update_period_in_days']) && !recent_error_logs?
52 52
     end
53 53
 
54 54
     def default_options
55 55
       {
56
-          :username => "tectonic",
57
-          :expected_update_period_in_days => "2",
58
-          :consumer_key => "---",
59
-          :consumer_secret => "---",
60
-          :oauth_token => "---",
61
-          :oauth_token_secret => "---"
56
+          'username' => "tectonic",
57
+          'expected_update_period_in_days' => "2",
58
+          'consumer_key' => "---",
59
+          'consumer_secret' => "---",
60
+          'oauth_token' => "---",
61
+          'oauth_token_secret' => "---"
62 62
       }
63 63
     end
64 64
 
65 65
     def check
66
-      since_id = memory[:since_id] || nil
66
+      since_id = memory['since_id'] || nil
67 67
       opts = {:count => 200, :include_rts => true, :exclude_replies => false, :include_entities => true, :contributor_details => true}
68 68
       opts.merge! :since_id => since_id unless since_id.nil?
69 69
 
70
-      tweets = Twitter.user_timeline(options[:username], opts)
70
+      tweets = Twitter.user_timeline(options['username'], opts)
71 71
 
72 72
       tweets.each do |tweet|
73
-        memory[:since_id] = tweet.id if !memory[:since_id] || (tweet.id > memory[:since_id])
73
+        memory['since_id'] = tweet.id if !memory['since_id'] || (tweet.id > memory['since_id'])
74 74
 
75 75
         create_event :payload => tweet.attrs
76 76
       end

+ 2 - 2
app/models/agents/user_location_agent.rb

@@ -34,11 +34,11 @@ module Agents
34 34
     end
35 35
 
36 36
     def default_options
37
-      { :secret => SecureRandom.hex(7) }
37
+      { 'secret' => SecureRandom.hex(7) }
38 38
     end
39 39
 
40 40
     def validate_options
41
-      errors.add(:base, "secret is required and must be longer than 4 characters") unless options[:secret].present? && options[:secret].length > 4
41
+      errors.add(:base, "secret is required and must be longer than 4 characters") unless options['secret'].present? && options['secret'].length > 4
42 42
     end
43 43
   end
44 44
 end

+ 8 - 8
app/models/agents/weather_agent.rb

@@ -45,30 +45,30 @@ module Agents
45 45
     end
46 46
 
47 47
     def wunderground
48
-      Wunderground.new(options[:api_key]) if key_setup?
48
+      Wunderground.new(options['api_key']) if key_setup?
49 49
     end
50 50
 
51 51
     def key_setup?
52
-      options[:api_key] && options[:api_key] != "your-key"
52
+      options['api_key'] && options['api_key'] != "your-key"
53 53
     end
54 54
 
55 55
     def default_options
56 56
       {
57
-        :api_key => "your-key",
58
-        :location => "94103"
57
+        'api_key' => "your-key",
58
+        'location' => "94103"
59 59
       }
60 60
     end
61 61
 
62 62
     def validate_options
63
-      errors.add(:base, "location is required") unless options[:location].present? || options[:zipcode].present?
64
-      errors.add(:base, "api_key is required") unless options[:api_key].present?
63
+      errors.add(:base, "location is required") unless options['location'].present? || options['zipcode'].present?
64
+      errors.add(:base, "api_key is required") unless options['api_key'].present?
65 65
     end
66 66
 
67 67
     def check
68 68
       if key_setup?
69
-        wunderground.forecast_for(options[:location] || options[:zipcode])["forecast"]["simpleforecast"]["forecastday"].each do |day|
69
+        wunderground.forecast_for(options['location'] || options['zipcode'])["forecast"]["simpleforecast"]["forecastday"].each do |day|
70 70
           if is_tomorrow?(day)
71
-            create_event :payload => day.merge(:location => options[:location] || options[:zipcode])
71
+            create_event :payload => day.merge('location' => options['location'] || options['zipcode'])
72 72
           end
73 73
         end
74 74
       end

+ 39 - 39
app/models/agents/website_agent.rb

@@ -15,19 +15,19 @@ module Agents
15 15
 
16 16
       To tell the Agent how to parse the content, specify `extract` as a hash with keys naming the extractions and values of hashes.
17 17
 
18
-      When parsing HTML or XML, these sub-hashes specify how to extract with a `:css` CSS selector and either `:text => true` or `attr` pointing to an attribute name to grab.  An example:
18
+      When parsing HTML or XML, these sub-hashes specify how to extract with a `css` CSS selector and either `'text': true` or `attr` pointing to an attribute name to grab.  An example:
19 19
 
20
-          :extract => {
21
-            :url => { :css => "#comic img", :attr => "src" },
22
-            :title => { :css => "#comic img", :attr => "title" },
23
-            :body_text => { :css => "div.main", :text => true }
20
+          'extract': {
21
+            'url': { 'css': "#comic img", 'attr': "src" },
22
+            'title': { 'css': "#comic img", 'attr': "title" },
23
+            'body_text': { 'css': "div.main", 'text': true }
24 24
           }
25 25
 
26 26
       When parsing JSON, these sub-hashes specify [JSONPaths](http://goessner.net/articles/JsonPath/) to the values that you care about.  For example:
27 27
 
28
-          :extract => {
29
-            :title => { :path => "results.data[*].title" },
30
-            :description => { :path => "results.data[*].description" }
28
+          'extract': {
29
+            'title': { 'path': "results.data[*].title" },
30
+            'description': { 'path': "results.data[*].description" }
31 31
           }
32 32
 
33 33
       Note that for all of the formats, whatever you extract MUST have the same number of matches for each extractor.  E.g., if you're extracting rows, all extractors must match all rows.  For generating CSS selectors, something like [SelectorGadget](http://selectorgadget.com) may be helpful.
@@ -36,7 +36,7 @@ module Agents
36 36
     MD
37 37
 
38 38
     event_description do
39
-      "Events will have the fields you specified.  Your options look like:\n\n    #{Utils.pretty_print options[:extract]}"
39
+      "Events will have the fields you specified.  Your options look like:\n\n    #{Utils.pretty_print options['extract']}"
40 40
     end
41 41
 
42 42
     default_schedule "every_12h"
@@ -44,33 +44,33 @@ module Agents
44 44
     UNIQUENESS_LOOK_BACK = 30
45 45
 
46 46
     def working?
47
-      event_created_within(options[:expected_update_period_in_days]) && !recent_error_logs?
47
+      event_created_within(options['expected_update_period_in_days']) && !recent_error_logs?
48 48
     end
49 49
 
50 50
     def default_options
51 51
       {
52
-          :expected_update_period_in_days => "2",
53
-          :url => "http://xkcd.com",
54
-          :type => "html",
55
-          :mode => :on_change,
56
-          :extract => {
57
-              :url => {:css => "#comic img", :attr => "src"},
58
-              :title => {:css => "#comic img", :attr => "title"}
52
+          'expected_update_period_in_days' => "2",
53
+          'url' => "http://xkcd.com",
54
+          'type' => "html",
55
+          'mode' => :on_change,
56
+          'extract' => {
57
+            'url' => {'css' => "#comic img", 'attr' => "src"},
58
+            'title' => {'css' => "#comic img", 'attr' => "title"}
59 59
           }
60 60
       }
61 61
     end
62 62
 
63 63
     def validate_options
64
-      errors.add(:base, "url and expected_update_period_in_days are required") unless options[:expected_update_period_in_days].present? && options[:url].present?
65
-      if !options[:extract].present? && extraction_type != "json"
64
+      errors.add(:base, "url and expected_update_period_in_days are required") unless options['expected_update_period_in_days'].present? && options['url'].present?
65
+      if !options['extract'].present? && extraction_type != "json"
66 66
         errors.add(:base, "extract is required for all types except json")
67 67
       end
68 68
     end
69 69
 
70 70
     def check
71 71
       hydra = Typhoeus::Hydra.new
72
-      log "Fetching #{options[:url]}"
73
-      request = Typhoeus::Request.new(options[:url], :followlocation => true)
72
+      log "Fetching #{options['url']}"
73
+      request = Typhoeus::Request.new(options['url'], :followlocation => true)
74 74
       request.on_failure do |response|
75 75
         error "Failed: #{response.inspect}"
76 76
       end
@@ -85,37 +85,37 @@ module Agents
85 85
           end
86 86
         else
87 87
           output = {}
88
-          options[:extract].each do |name, extraction_details|
88
+          options['extract'].each do |name, extraction_details|
89 89
             result = if extraction_type == "json"
90
-                       output[name] = Utils.values_at(doc, extraction_details[:path])
90
+                       output[name] = Utils.values_at(doc, extraction_details['path'])
91 91
                      else
92
-                       output[name] = doc.css(extraction_details[:css]).map { |node|
93
-                         if extraction_details[:attr]
94
-                           node.attr(extraction_details[:attr])
95
-                         elsif extraction_details[:text]
92
+                       output[name] = doc.css(extraction_details['css']).map { |node|
93
+                         if extraction_details['attr']
94
+                           node.attr(extraction_details['attr'])
95
+                         elsif extraction_details['text']
96 96
                            node.text()
97 97
                          else
98
-                           error ":attr or :text is required on HTML or XML extraction patterns"
98
+                           error "'attr' or 'text' is required on HTML or XML extraction patterns"
99 99
                            return
100 100
                          end
101 101
                        }
102 102
                      end
103
-            log "Extracting #{extraction_type} at #{extraction_details[:path] || extraction_details[:css]}: #{result}"
103
+            log "Extracting #{extraction_type} at #{extraction_details['path'] || extraction_details['css']}: #{result}"
104 104
           end
105 105
 
106
-          num_unique_lengths = options[:extract].keys.map { |name| output[name].length }.uniq
106
+          num_unique_lengths = options['extract'].keys.map { |name| output[name].length }.uniq
107 107
 
108 108
           if num_unique_lengths.length != 1
109
-            error "Got an uneven number of matches for #{options[:name]}: #{options[:extract].inspect}"
109
+            error "Got an uneven number of matches for #{options['name']}: #{options['extract'].inspect}"
110 110
             return
111 111
           end
112 112
       
113 113
           num_unique_lengths.first.times do |index|
114 114
             result = {}
115
-            options[:extract].keys.each do |name|
115
+            options['extract'].keys.each do |name|
116 116
               result[name] = output[name][index]
117 117
               if name.to_s == 'url'
118
-                result[name] = URI.join(options[:url], result[name]).to_s if (result[name] =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]).nil?
118
+                result[name] = URI.join(options['url'], result[name]).to_s if (result[name] =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]).nil?
119 119
               end
120 120
             end
121 121
 
@@ -133,22 +133,22 @@ module Agents
133 133
     private
134 134
 
135 135
     def store_payload? result
136
-      !options[:mode] || options[:mode].to_s == "all" || (options[:mode].to_s == "on_change" && !previous_payloads.include?(result.to_json))
136
+      !options['mode'] || options['mode'].to_s == "all" || (options['mode'].to_s == "on_change" && !previous_payloads.include?(result.to_json))
137 137
     end
138 138
 
139 139
     def previous_payloads
140
-      events.order("id desc").limit(UNIQUENESS_LOOK_BACK).pluck(:payload).map(&:to_json) if options[:mode].to_s == "on_change"
140
+      events.order("id desc").limit(UNIQUENESS_LOOK_BACK).pluck(:payload).map(&:to_json) if options['mode'].to_s == "on_change"
141 141
     end
142 142
 
143 143
     def extract_full_json?
144
-      (!options[:extract].present? && extraction_type == "json")
144
+      (!options['extract'].present? && extraction_type == "json")
145 145
     end
146 146
 
147 147
     def extraction_type
148
-      (options[:type] || begin
149
-        if options[:url] =~ /\.(rss|xml)$/i
148
+      (options['type'] || begin
149
+        if options['url'] =~ /\.(rss|xml)$/i
150 150
           "xml"
151
-        elsif options[:url] =~ /\.json$/i
151
+        elsif options['url'] =~ /\.json$/i
152 152
           "json"
153 153
         else
154 154
           "html"

+ 19 - 19
app/models/agents/weibo_publish_agent.rb

@@ -20,24 +20,24 @@ module Agents
20 20
     MD
21 21
 
22 22
     def validate_options
23
-      unless options[:uid].present? &&
24
-        options[:expected_update_period_in_days].present?
23
+      unless options['uid'].present? &&
24
+        options['expected_update_period_in_days'].present?
25 25
         errors.add(:base, "expected_update_period_in_days and uid are required")
26 26
       end
27 27
     end
28 28
 
29 29
     def working?
30
-      (event = event_created_within(options[:expected_update_period_in_days])) && event.payload[:success] == true && !recent_error_logs?
30
+      (event = event_created_within(options['expected_update_period_in_days'])) && event.payload['success'] == true && !recent_error_logs?
31 31
     end
32 32
 
33 33
     def default_options
34 34
       {
35
-          :uid => "",
36
-          :access_token => "---",
37
-          :app_key => "---",
38
-          :app_secret => "---",
39
-          :expected_update_period_in_days => "10",
40
-          :message_path => "text"
35
+        'uid' => "",
36
+        'access_token' => "---",
37
+        'app_key' => "---",
38
+        'app_secret' => "---",
39
+        'expected_update_period_in_days' => "10",
40
+        'message_path' => "text"
41 41
       }
42 42
     end
43 43
 
@@ -47,25 +47,25 @@ module Agents
47 47
         incoming_events = incoming_events.first(20)
48 48
       end
49 49
       incoming_events.each do |event|
50
-        tweet_text = Utils.value_at(event.payload, options[:message_path])
50
+        tweet_text = Utils.value_at(event.payload, options['message_path'])
51 51
         if event.agent.type == "Agents::TwitterUserAgent"
52 52
           tweet_text = unwrap_tco_urls(tweet_text, event.payload)
53 53
         end
54 54
         begin
55 55
           publish_tweet tweet_text
56 56
           create_event :payload => {
57
-            :success => true,
58
-            :published_tweet => tweet_text,
59
-            :agent_id => event.agent_id,
60
-            :event_id => event.id
57
+            'success' => true,
58
+            'published_tweet' => tweet_text,
59
+            'agent_id' => event.agent_id,
60
+            'event_id' => event.id
61 61
           }
62 62
         rescue OAuth2::Error => e
63 63
           create_event :payload => {
64
-            :success => false,
65
-            :error => e.message,
66
-            :failed_tweet => tweet_text,
67
-            :agent_id => event.agent_id,
68
-            :event_id => event.id
64
+            'success' => false,
65
+            'error' => e.message,
66
+            'failed_tweet' => tweet_text,
67
+            'agent_id' => event.agent_id,
68
+            'event_id' => event.id
69 69
           }
70 70
         end
71 71
       end

+ 11 - 11
app/models/agents/weibo_user_agent.rb

@@ -70,29 +70,29 @@ module Agents
70 70
     default_schedule "every_1h"
71 71
 
72 72
     def validate_options
73
-      unless options[:uid].present? &&
74
-        options[:expected_update_period_in_days].present?
73
+      unless options['uid'].present? &&
74
+        options['expected_update_period_in_days'].present?
75 75
         errors.add(:base, "expected_update_period_in_days and uid are required")
76 76
       end
77 77
     end
78 78
 
79 79
     def working?
80
-      event_created_within(options[:expected_update_period_in_days]) && !recent_error_logs?
80
+      event_created_within(options['expected_update_period_in_days']) && !recent_error_logs?
81 81
     end
82 82
 
83 83
     def default_options
84 84
       {
85
-          :uid => "",
86
-          :access_token => "---",
87
-          :app_key => "---",
88
-          :app_secret => "---",
89
-          :expected_update_period_in_days => "2"
85
+        'uid' => "",
86
+        'access_token' => "---",
87
+        'app_key' => "---",
88
+        'app_secret' => "---",
89
+        'expected_update_period_in_days' => "2"
90 90
       }
91 91
     end
92 92
 
93 93
     def check
94
-      since_id = memory[:since_id] || nil
95
-      opts = {:uid => options[:uid].to_i}
94
+      since_id = memory['since_id'] || nil
95
+      opts = {:uid => options['uid'].to_i}
96 96
       opts.merge! :since_id => since_id unless since_id.nil?
97 97
 
98 98
       # http://open.weibo.com/wiki/2/statuses/user_timeline/en
@@ -101,7 +101,7 @@ module Agents
101 101
 
102 102
 
103 103
         resp[:statuses].each do |status|
104
-          memory[:since_id] = status.id if !memory[:since_id] || (status.id > memory[:since_id])
104
+          memory['since_id'] = status.id if !memory['since_id'] || (status.id > memory['since_id'])
105 105
 
106 106
           create_event :payload => status.as_json
107 107
         end

+ 7 - 4
app/models/event.rb

@@ -1,13 +1,16 @@
1
-require 'serialize_and_normalize'
1
+require 'json_with_indifferent_access'
2 2
 
3 3
 class Event < ActiveRecord::Base
4
-  include SerializeAndNormalize
5
-
6 4
   attr_accessible :lat, :lng, :payload, :user_id, :user, :expires_at
7 5
 
8 6
   acts_as_mappable
9 7
 
10
-  serialize_and_normalize :payload
8
+  serialize :payload, JSONWithIndifferentAccess
9
+
10
+  def payload=(o)
11
+    self[:payload] = ActiveSupport::HashWithIndifferentAccess.new(o)
12
+  end
13
+
11 14
 
12 15
   belongs_to :user
13 16
   belongs_to :agent, :counter_cache => true

+ 9 - 0
lib/json_with_indifferent_access.rb

@@ -0,0 +1,9 @@
1
+class JSONWithIndifferentAccess
2
+  def self.load(json)
3
+    ActiveSupport::HashWithIndifferentAccess.new(JSON.load(json || '{}'))
4
+  end
5
+
6
+  def self.dump(hash)
7
+    JSON.dump(hash)
8
+  end
9
+end

+ 0 - 46
lib/serialize_and_normalize.rb

@@ -1,46 +0,0 @@
1
-module SerializeAndNormalize
2
-  extend ActiveSupport::Concern
3
-
4
-  module ClassMethods
5
-    def serialize_and_normalize(*column_names)
6
-      column_names.flatten.uniq.compact.map(&:to_sym).each do |column_name|
7
-        setup_name = "setup_#{column_name}".to_sym
8
-        normalize_name = "normalize_#{column_name}".to_sym
9
-        validate_name = "validate_#{column_name}".to_sym
10
-
11
-        serialize column_name, JSON
12
-        after_initialize setup_name
13
-        before_validation normalize_name
14
-        before_save normalize_name
15
-        validate validate_name
16
-
17
-        class_eval <<-RUBY
18
-          def #{setup_name}
19
-            self[:#{column_name}] ||= ActiveSupport::HashWithIndifferentAccess.new
20
-          end
21
-
22
-          def #{validate_name}
23
-            # Implement me in your subclass.
24
-          end
25
-
26
-          def #{normalize_name}
27
-            self.#{column_name} = self[:#{column_name}]
28
-          end
29
-
30
-          def #{column_name}=(data)
31
-            data = (JSON.parse(data) rescue data) if data.is_a?(String)
32
-
33
-            case data
34
-              when ActiveSupport::HashWithIndifferentAccess
35
-                self[:#{column_name}] = data
36
-              when Hash
37
-                self[:#{column_name}] = ActiveSupport::HashWithIndifferentAccess.new(data)
38
-              else
39
-                self[:#{column_name}] = data
40
-            end
41
-          end
42
-        RUBY
43
-      end
44
-    end
45
-  end
46
-end

+ 1 - 1
spec/controllers/agents_controller_spec.rb

@@ -5,7 +5,7 @@ describe AgentsController do
5 5
     {
6 6
         :type => "Agents::WebsiteAgent",
7 7
         :name => "Something",
8
-        :options => agents(:bob_website_agent).options.to_json,
8
+        :options => agents(:bob_website_agent).options,
9 9
         :source_ids => [agents(:bob_weather_agent).id, ""]
10 10
     }.merge(options)
11 11
   end

+ 7 - 7
spec/fixtures/agents.yml

@@ -11,7 +11,7 @@ jane_website_agent:
11 11
                      :title => {:css => "item title", :text => true},
12 12
                      :url => {:css => "item link", :text => true}
13 13
                  }
14
-               }.to_yaml.inspect %>
14
+               }.to_json.inspect %>
15 15
 
16 16
 bob_website_agent:
17 17
   type: Agents::WebsiteAgent
@@ -26,7 +26,7 @@ bob_website_agent:
26 26
                    :url => {:css => "#comic img", :attr => "src"},
27 27
                    :title => {:css => "#comic img", :attr => "title"}
28 28
                  }
29
-               }.to_yaml.inspect %>
29
+               }.to_json.inspect %>
30 30
 
31 31
 bob_weather_agent:
32 32
   type: Agents::WeatherAgent
@@ -38,7 +38,7 @@ bob_weather_agent:
38 38
                  :lat => 37.779329,
39 39
                  :lng => -122.41915,
40 40
                  :api_key => 'test'
41
-               }.to_yaml.inspect %>
41
+               }.to_json.inspect %>
42 42
 
43 43
 jane_weather_agent:
44 44
   type: Agents::WeatherAgent
@@ -50,7 +50,7 @@ jane_weather_agent:
50 50
                  :lat => 37.779329,
51 51
                  :lng => -122.41915,
52 52
                  :api_key => 'test'
53
-               }.to_yaml.inspect %>
53
+               }.to_json.inspect %>
54 54
 
55 55
 jane_rain_notifier_agent:
56 56
   type: Agents::TriggerAgent
@@ -64,7 +64,7 @@ jane_rain_notifier_agent:
64 64
                    :path => "conditions"
65 65
                  }],
66 66
                  :message => "Just so you know, it looks like '<conditions>' tomorrow in <location>"
67
-               }.to_yaml.inspect %>
67
+               }.to_json.inspect %>
68 68
 
69 69
 bob_rain_notifier_agent:
70 70
   type: Agents::TriggerAgent
@@ -78,7 +78,7 @@ bob_rain_notifier_agent:
78 78
                    :path => "conditions"
79 79
                   }],
80 80
                  :message => "Just so you know, it looks like '<conditions>' tomorrow in <location>"
81
-               }.to_yaml.inspect %>
81
+               }.to_json.inspect %>
82 82
 
83 83
 bob_twitter_user_agent:
84 84
   type: Agents::TwitterUserAgent
@@ -91,7 +91,7 @@ bob_twitter_user_agent:
91 91
       :consumer_secret => "---",
92 92
       :oauth_token => "---",
93 93
       :oauth_token_secret => "---"
94
-    }.to_yaml.inspect %>
94
+    }.to_json.inspect %>
95 95
 
96 96
 bob_manual_event_agent:
97 97
   type: Agents::ManualEventAgent

+ 2 - 2
spec/fixtures/events.yml

@@ -1,9 +1,9 @@
1 1
 bob_website_agent_event:
2 2
   user: bob
3 3
   agent: bob_website_agent
4
-  payload: <%= [{ :title => "foo", :url => "http://foo.com" }].to_yaml.inspect %>
4
+  payload: <%= [{ :title => "foo", :url => "http://foo.com" }].to_json.inspect %>
5 5
 
6 6
 jane_website_agent_event:
7 7
   user: jane
8 8
   agent: jane_website_agent
9
-  payload: <%= [{ :title => "foo", :url => "http://foo.com" }].to_yaml.inspect %>
9
+  payload: <%= [{ :title => "foo", :url => "http://foo.com" }].to_json.inspect %>

+ 2 - 2
spec/models/agent_spec.rb

@@ -261,9 +261,9 @@ describe Agent do
261 261
       it "symbolizes memory before validating" do
262 262
         agent = Agents::SomethingSource.new(:name => "something")
263 263
         agent.user = users(:bob)
264
-        agent.memory["bad"] = :hello
264
+        agent.memory["bad"] = 2
265 265
         agent.save
266
-        agent.memory[:bad].should == :hello
266
+        agent.memory[:bad].should == 2
267 267
       end
268 268
 
269 269
       it "should not allow agents owned by other people" do

+ 5 - 5
spec/models/agents/digest_email_agent_spec.rb

@@ -19,16 +19,16 @@ describe Agents::DigestEmailAgent do
19 19
     it "queues any payloads it receives" do
20 20
       event1 = Event.new
21 21
       event1.agent = agents(:bob_rain_notifier_agent)
22
-      event1.payload = "Something you should know about"
22
+      event1.payload = { :data => "Something you should know about" }
23 23
       event1.save!
24 24
 
25 25
       event2 = Event.new
26 26
       event2.agent = agents(:bob_weather_agent)
27
-      event2.payload = "Something else you should know about"
27
+      event2.payload = { :data => "Something else you should know about" }
28 28
       event2.save!
29 29
 
30 30
       Agents::DigestEmailAgent.async_receive(@checker.id, [event1.id, event2.id])
31
-      @checker.reload.memory[:queue].should == ["Something you should know about", "Something else you should know about"]
31
+      @checker.reload.memory[:queue].should == [{ 'data' => "Something you should know about" }, { 'data' => "Something else you should know about" }]
32 32
     end
33 33
   end
34 34
 
@@ -37,7 +37,7 @@ describe Agents::DigestEmailAgent do
37 37
       Agents::DigestEmailAgent.async_check(@checker.id)
38 38
       ActionMailer::Base.deliveries.should == []
39 39
 
40
-      @checker.memory[:queue] = ["Something you should know about",
40
+      @checker.memory[:queue] = [{ :data => "Something you should know about" },
41 41
                                  { :title => "Foo", :url => "http://google.com", :bar => 2 },
42 42
                                  { "message" => "hi", :woah => "there" },
43 43
                                  { "test" => 2 }]
@@ -47,7 +47,7 @@ describe Agents::DigestEmailAgent do
47 47
       Agents::DigestEmailAgent.async_check(@checker.id)
48 48
       ActionMailer::Base.deliveries.last.to.should == ["bob@example.com"]
49 49
       ActionMailer::Base.deliveries.last.subject.should == "something interesting"
50
-      get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Something you should know about\n\nFoo\n  bar: 2\n  url: http://google.com\n\nhi\n  woah: there\n\nEvent\n  test: 2"
50
+      get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Event\n  data: Something you should know about\n\nFoo\n  bar: 2\n  url: http://google.com\n\nhi\n  woah: there\n\nEvent\n  test: 2"
51 51
       @checker.reload.memory[:queue].should be_empty
52 52
     end
53 53
 

+ 4 - 4
spec/models/agents/email_agent_spec.rb

@@ -21,12 +21,12 @@ describe Agents::EmailAgent do
21 21
 
22 22
       event1 = Event.new
23 23
       event1.agent = agents(:bob_rain_notifier_agent)
24
-      event1.payload = "Something you should know about"
24
+      event1.payload = { :data => "Something you should know about" }
25 25
       event1.save!
26 26
 
27 27
       event2 = Event.new
28 28
       event2.agent = agents(:bob_weather_agent)
29
-      event2.payload = "Something else you should know about"
29
+      event2.payload = { :data => "Something else you should know about" }
30 30
       event2.save!
31 31
 
32 32
       Agents::EmailAgent.async_receive(@checker.id, [event1.id])
@@ -35,8 +35,8 @@ describe Agents::EmailAgent do
35 35
       ActionMailer::Base.deliveries.count.should == 2
36 36
       ActionMailer::Base.deliveries.last.to.should == ["bob@example.com"]
37 37
       ActionMailer::Base.deliveries.last.subject.should == "something interesting"
38
-      get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Something else you should know about"
39
-      get_message_part(ActionMailer::Base.deliveries.first, /plain/).strip.should == "Something you should know about"
38
+      get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Event\n  data: Something else you should know about"
39
+      get_message_part(ActionMailer::Base.deliveries.first, /plain/).strip.should == "Event\n  data: Something you should know about"
40 40
     end
41 41
 
42 42
     it "can receive complex events and send them on" do

+ 97 - 97
spec/models/agents/human_task_agent_spec.rb

@@ -9,8 +9,8 @@ describe Agents::HumanTaskAgent do
9 9
 
10 10
     @event = Event.new
11 11
     @event.agent = agents(:bob_rain_notifier_agent)
12
-    @event.payload = { :foo => { "bar" => { :baz => "a2b" } },
13
-                       :name => "Joe" }
12
+    @event.payload = { 'foo' => { "bar" => { 'baz' => "a2b" } },
13
+                       'name' => "Joe" }
14 14
     @event.id = 345
15 15
 
16 16
     @checker.should be_valid
@@ -18,110 +18,110 @@ describe Agents::HumanTaskAgent do
18 18
 
19 19
   describe "validations" do
20 20
     it "validates that trigger_on is 'schedule' or 'event'" do
21
-      @checker.options[:trigger_on] = "foo"
21
+      @checker.options['trigger_on'] = "foo"
22 22
       @checker.should_not be_valid
23 23
     end
24 24
 
25 25
     it "requires expected_receive_period_in_days when trigger_on is set to 'event'" do
26
-      @checker.options[:trigger_on] = "event"
27
-      @checker.options[:expected_receive_period_in_days] = nil
26
+      @checker.options['trigger_on'] = "event"
27
+      @checker.options['expected_receive_period_in_days'] = nil
28 28
       @checker.should_not be_valid
29
-      @checker.options[:expected_receive_period_in_days] = 2
29
+      @checker.options['expected_receive_period_in_days'] = 2
30 30
       @checker.should be_valid
31 31
     end
32 32
 
33 33
     it "requires a positive submission_period when trigger_on is set to 'schedule'" do
34
-      @checker.options[:trigger_on] = "schedule"
35
-      @checker.options[:submission_period] = nil
34
+      @checker.options['trigger_on'] = "schedule"
35
+      @checker.options['submission_period'] = nil
36 36
       @checker.should_not be_valid
37
-      @checker.options[:submission_period] = 2
37
+      @checker.options['submission_period'] = 2
38 38
       @checker.should be_valid
39 39
     end
40 40
 
41 41
     it "requires a hit.title" do
42
-      @checker.options[:hit][:title] = ""
42
+      @checker.options['hit']['title'] = ""
43 43
       @checker.should_not be_valid
44 44
     end
45 45
 
46 46
     it "requires a hit.description" do
47
-      @checker.options[:hit][:description] = ""
47
+      @checker.options['hit']['description'] = ""
48 48
       @checker.should_not be_valid
49 49
     end
50 50
 
51 51
     it "requires hit.assignments" do
52
-      @checker.options[:hit][:assignments] = ""
52
+      @checker.options['hit']['assignments'] = ""
53 53
       @checker.should_not be_valid
54
-      @checker.options[:hit][:assignments] = 0
54
+      @checker.options['hit']['assignments'] = 0
55 55
       @checker.should_not be_valid
56
-      @checker.options[:hit][:assignments] = "moose"
56
+      @checker.options['hit']['assignments'] = "moose"
57 57
       @checker.should_not be_valid
58
-      @checker.options[:hit][:assignments] = "2"
58
+      @checker.options['hit']['assignments'] = "2"
59 59
       @checker.should be_valid
60 60
     end
61 61
 
62 62
     it "requires hit.questions" do
63
-      old_questions = @checker.options[:hit][:questions]
64
-      @checker.options[:hit][:questions] = nil
63
+      old_questions = @checker.options['hit']['questions']
64
+      @checker.options['hit']['questions'] = nil
65 65
       @checker.should_not be_valid
66
-      @checker.options[:hit][:questions] = []
66
+      @checker.options['hit']['questions'] = []
67 67
       @checker.should_not be_valid
68
-      @checker.options[:hit][:questions] = [old_questions[0]]
68
+      @checker.options['hit']['questions'] = [old_questions[0]]
69 69
       @checker.should be_valid
70 70
     end
71 71
 
72 72
     it "requires that all questions have key, name, required, type, and question" do
73
-      old_questions = @checker.options[:hit][:questions]
74
-      @checker.options[:hit][:questions].first[:key] = ""
73
+      old_questions = @checker.options['hit']['questions']
74
+      @checker.options['hit']['questions'].first['key'] = ""
75 75
       @checker.should_not be_valid
76 76
 
77
-      @checker.options[:hit][:questions] = old_questions
78
-      @checker.options[:hit][:questions].first[:name] = ""
77
+      @checker.options['hit']['questions'] = old_questions
78
+      @checker.options['hit']['questions'].first['name'] = ""
79 79
       @checker.should_not be_valid
80 80
 
81
-      @checker.options[:hit][:questions] = old_questions
82
-      @checker.options[:hit][:questions].first[:required] = nil
81
+      @checker.options['hit']['questions'] = old_questions
82
+      @checker.options['hit']['questions'].first['required'] = nil
83 83
       @checker.should_not be_valid
84 84
 
85
-      @checker.options[:hit][:questions] = old_questions
86
-      @checker.options[:hit][:questions].first[:type] = ""
85
+      @checker.options['hit']['questions'] = old_questions
86
+      @checker.options['hit']['questions'].first['type'] = ""
87 87
       @checker.should_not be_valid
88 88
 
89
-      @checker.options[:hit][:questions] = old_questions
90
-      @checker.options[:hit][:questions].first[:question] = ""
89
+      @checker.options['hit']['questions'] = old_questions
90
+      @checker.options['hit']['questions'].first['question'] = ""
91 91
       @checker.should_not be_valid
92 92
     end
93 93
 
94 94
     it "requires that all questions of type 'selection' have a selections array with keys and text" do
95
-      @checker.options[:hit][:questions][0][:selections] = []
95
+      @checker.options['hit']['questions'][0]['selections'] = []
96 96
       @checker.should_not be_valid
97
-      @checker.options[:hit][:questions][0][:selections] = [{}]
97
+      @checker.options['hit']['questions'][0]['selections'] = [{}]
98 98
       @checker.should_not be_valid
99
-      @checker.options[:hit][:questions][0][:selections] = [{ :key => "", :text => "" }]
99
+      @checker.options['hit']['questions'][0]['selections'] = [{ 'key' => "", 'text' => "" }]
100 100
       @checker.should_not be_valid
101
-      @checker.options[:hit][:questions][0][:selections] = [{ :key => "", :text => "hi" }]
101
+      @checker.options['hit']['questions'][0]['selections'] = [{ 'key' => "", 'text' => "hi" }]
102 102
       @checker.should_not be_valid
103
-      @checker.options[:hit][:questions][0][:selections] = [{ :key => "hi", :text => "" }]
103
+      @checker.options['hit']['questions'][0]['selections'] = [{ 'key' => "hi", 'text' => "" }]
104 104
       @checker.should_not be_valid
105
-      @checker.options[:hit][:questions][0][:selections] = [{ :key => "hi", :text => "hi" }]
105
+      @checker.options['hit']['questions'][0]['selections'] = [{ 'key' => "hi", 'text' => "hi" }]
106 106
       @checker.should be_valid
107
-      @checker.options[:hit][:questions][0][:selections] = [{ :key => "hi", :text => "hi" }, {}]
107
+      @checker.options['hit']['questions'][0]['selections'] = [{ 'key' => "hi", 'text' => "hi" }, {}]
108 108
       @checker.should_not be_valid
109 109
     end
110 110
 
111 111
     it "requires that all questions be of type 'selection' when `take_majority` is `true`" do
112
-      @checker.options[:take_majority] = "true"
112
+      @checker.options['take_majority'] = "true"
113 113
       @checker.should_not be_valid
114
-      @checker.options[:hit][:questions][1][:type] = "selection"
115
-      @checker.options[:hit][:questions][1][:selections] = @checker.options[:hit][:questions][0][:selections]
114
+      @checker.options['hit']['questions'][1]['type'] = "selection"
115
+      @checker.options['hit']['questions'][1]['selections'] = @checker.options['hit']['questions'][0]['selections']
116 116
       @checker.should be_valid
117 117
     end
118 118
   end
119 119
 
120 120
   describe "when 'trigger_on' is set to 'schedule'" do
121 121
     before do
122
-      @checker.options[:trigger_on] = "schedule"
123
-      @checker.options[:submission_period] = "2"
124
-      @checker.options.delete(:expected_receive_period_in_days)
122
+      @checker.options['trigger_on'] = "schedule"
123
+      @checker.options['submission_period'] = "2"
124
+      @checker.options.delete('expected_receive_period_in_days')
125 125
     end
126 126
 
127 127
     it "should check for reviewable HITs frequently" do
@@ -151,7 +151,7 @@ describe Agents::HumanTaskAgent do
151 151
 
152 152
   describe "when 'trigger_on' is set to 'event'" do
153 153
     it "should not create HITs during check but should check for reviewable HITs" do
154
-      @checker.options[:submission_period] = "2"
154
+      @checker.options['submission_period'] = "2"
155 155
       now = Time.now
156 156
       stub(Time).now { now }
157 157
       mock(@checker).review_hits.times(3)
@@ -171,9 +171,9 @@ describe Agents::HumanTaskAgent do
171 171
 
172 172
   describe "creating hits" do
173 173
     it "can create HITs based on events, interpolating their values" do
174
-      @checker.options[:hit][:title] = "Hi <.name>"
175
-      @checker.options[:hit][:description] = "Make something for <.name>"
176
-      @checker.options[:hit][:questions][0][:name] = "<.name> Question 1"
174
+      @checker.options['hit']['title'] = "Hi <.name>"
175
+      @checker.options['hit']['description'] = "Make something for <.name>"
176
+      @checker.options['hit']['questions'][0]['name'] = "<.name> Question 1"
177 177
 
178 178
       question_form = nil
179 179
       hitInterface = OpenStruct.new
@@ -183,8 +183,8 @@ describe Agents::HumanTaskAgent do
183 183
 
184 184
       @checker.send :create_hit, @event
185 185
 
186
-      hitInterface.max_assignments.should == @checker.options[:hit][:assignments]
187
-      hitInterface.reward.should == @checker.options[:hit][:reward]
186
+      hitInterface.max_assignments.should == @checker.options['hit']['assignments']
187
+      hitInterface.reward.should == @checker.options['hit']['reward']
188 188
       hitInterface.description.should == "Make something for Joe"
189 189
 
190 190
       xml = question_form.to_xml
@@ -192,18 +192,18 @@ describe Agents::HumanTaskAgent do
192 192
       xml.should include("<Text>Make something for Joe</Text>")
193 193
       xml.should include("<DisplayName>Joe Question 1</DisplayName>")
194 194
 
195
-      @checker.memory[:hits][123].should == @event.id
195
+      @checker.memory['hits'][123].should == @event.id
196 196
     end
197 197
 
198 198
     it "works without an event too" do
199
-      @checker.options[:hit][:title] = "Hi <.name>"
199
+      @checker.options['hit']['title'] = "Hi <.name>"
200 200
       hitInterface = OpenStruct.new
201 201
       hitInterface.id = 123
202 202
       mock(hitInterface).question_form(instance_of Agents::HumanTaskAgent::AgentQuestionForm)
203 203
       mock(RTurk::Hit).create(:title => "Hi").yields(hitInterface) { hitInterface }
204 204
       @checker.send :create_hit
205
-      hitInterface.max_assignments.should == @checker.options[:hit][:assignments]
206
-      hitInterface.reward.should == @checker.options[:hit][:reward]
205
+      hitInterface.max_assignments.should == @checker.options['hit']['assignments']
206
+      hitInterface.reward.should == @checker.options['hit']['reward']
207 207
     end
208 208
   end
209 209
 
@@ -253,14 +253,14 @@ describe Agents::HumanTaskAgent do
253 253
     it "should work on multiple HITs" do
254 254
       event2 = Event.new
255 255
       event2.agent = agents(:bob_rain_notifier_agent)
256
-      event2.payload = { :foo2 => { "bar2" => { :baz2 => "a2b2" } },
257
-                          :name2 => "Joe2" }
256
+      event2.payload = { 'foo2' => { "bar2" => { 'baz2' => "a2b2" } },
257
+                         'name2' => "Joe2" }
258 258
       event2.id = 3452
259 259
 
260 260
       # It knows about two HITs from two different events.
261
-      @checker.memory[:hits] = {}
262
-      @checker.memory[:hits][:"JH3132836336DHG"] = @event.id
263
-      @checker.memory[:hits][:"JH39AA63836DHG"] = event2.id
261
+      @checker.memory['hits'] = {}
262
+      @checker.memory['hits']["JH3132836336DHG"] = @event.id
263
+      @checker.memory['hits']["JH39AA63836DHG"] = event2.id
264 264
 
265 265
       hit_ids = %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]
266 266
       mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { hit_ids } } # It sees 3 HITs.
@@ -273,7 +273,7 @@ describe Agents::HumanTaskAgent do
273 273
     end
274 274
 
275 275
     it "shouldn't do anything if an assignment isn't ready" do
276
-      @checker.memory[:hits] = { :"JH3132836336DHG" => @event.id }
276
+      @checker.memory['hits'] = { "JH3132836336DHG" => @event.id }
277 277
       mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
278 278
       assignments = [
279 279
         FakeAssignment.new(:status => "Accepted", :answers => {}),
@@ -288,11 +288,11 @@ describe Agents::HumanTaskAgent do
288 288
       @checker.send :review_hits
289 289
 
290 290
       assignments.all? {|a| a.approved == true }.should be_false
291
-      @checker.memory[:hits].should == { "JH3132836336DHG" => @event.id }
291
+      @checker.memory['hits'].should == { "JH3132836336DHG" => @event.id }
292 292
     end
293 293
 
294 294
     it "shouldn't do anything if an assignment is missing" do
295
-      @checker.memory[:hits] = { :"JH3132836336DHG" => @event.id }
295
+      @checker.memory['hits'] = { "JH3132836336DHG" => @event.id }
296 296
       mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
297 297
       assignments = [
298 298
         FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"happy", "feedback"=>"Take 2"})
@@ -306,11 +306,11 @@ describe Agents::HumanTaskAgent do
306 306
       @checker.send :review_hits
307 307
 
308 308
       assignments.all? {|a| a.approved == true }.should be_false
309
-      @checker.memory[:hits].should == { "JH3132836336DHG" => @event.id }
309
+      @checker.memory['hits'].should == { "JH3132836336DHG" => @event.id }
310 310
     end
311 311
 
312 312
     it "should create events when all assignments are ready" do
313
-      @checker.memory[:hits] = { :"JH3132836336DHG" => @event.id }
313
+      @checker.memory['hits'] = { "JH3132836336DHG" => @event.id }
314 314
       mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
315 315
       assignments = [
316 316
         FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"neutral", "feedback"=>""}),
@@ -327,32 +327,32 @@ describe Agents::HumanTaskAgent do
327 327
       assignments.all? {|a| a.approved == true }.should be_true
328 328
       hit.should be_disposed
329 329
 
330
-      @checker.events.last.payload[:answers].should == [
330
+      @checker.events.last.payload['answers'].should == [
331 331
         {'sentiment' => "neutral", 'feedback' => ""},
332 332
         {'sentiment' => "happy", 'feedback' => "Take 2"}
333 333
       ]
334 334
 
335
-      @checker.memory[:hits].should == {}
335
+      @checker.memory['hits'].should == {}
336 336
     end
337 337
 
338 338
     describe "taking majority votes" do
339 339
       before do
340
-        @checker.options[:take_majority] = "true"
341
-        @checker.memory[:hits] = { "JH3132836336DHG" => @event.id }
340
+        @checker.options['take_majority'] = "true"
341
+        @checker.memory['hits'] = { "JH3132836336DHG" => @event.id }
342 342
         mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
343 343
       end
344 344
 
345 345
       it "should take the majority votes of all questions" do
346
-        @checker.options[:hit][:questions][1] = {
347
-          :type => "selection",
348
-          :key => "age_range",
349
-          :name => "Age Range",
350
-          :required => "true",
351
-          :question => "Please select your age range:",
352
-          :selections =>
346
+        @checker.options['hit']['questions'][1] = {
347
+          'type' => "selection",
348
+          'key' => "age_range",
349
+          'name' => "Age Range",
350
+          'required' => "true",
351
+          'question' => "Please select your age range:",
352
+          'selections' =>
353 353
             [
354
-              { :key => "<50", :text => "50 years old or younger" },
355
-              { :key => ">50", :text => "Over 50 years old" }
354
+              { 'key' => "<50", 'text' => "50 years old or younger" },
355
+              { 'key' => ">50", 'text' => "Over 50 years old" }
356 356
             ]
357 357
         }
358 358
 
@@ -371,35 +371,35 @@ describe Agents::HumanTaskAgent do
371 371
 
372 372
         assignments.all? {|a| a.approved == true }.should be_true
373 373
 
374
-        @checker.events.last.payload[:answers].should == [
374
+        @checker.events.last.payload['answers'].should == [
375 375
           { 'sentiment' => "sad", 'age_range' => "<50" },
376 376
           { 'sentiment' => "neutral", 'age_range' => ">50" },
377 377
           { 'sentiment' => "happy", 'age_range' => ">50" },
378 378
           { 'sentiment' => "happy", 'age_range' => ">50" }
379 379
         ]
380 380
 
381
-        @checker.events.last.payload[:counts].should == { 'sentiment' => { 'happy' => 2, 'sad' => 1, 'neutral' => 1 }, 'age_range' => { ">50" => 3, "<50" => 1 } }
382
-        @checker.events.last.payload[:majority_answer].should == { 'sentiment' => "happy", 'age_range' => ">50" }
383
-        @checker.events.last.payload.should_not have_key(:average_answer)
381
+        @checker.events.last.payload['counts'].should == { 'sentiment' => { 'happy' => 2, 'sad' => 1, 'neutral' => 1 }, 'age_range' => { ">50" => 3, "<50" => 1 } }
382
+        @checker.events.last.payload['majority_answer'].should == { 'sentiment' => "happy", 'age_range' => ">50" }
383
+        @checker.events.last.payload.should_not have_key('average_answer')
384 384
 
385
-        @checker.memory[:hits].should == {}
385
+        @checker.memory['hits'].should == {}
386 386
       end
387 387
 
388 388
       it "should also provide an average answer when all questions are numeric" do
389
-        @checker.options[:hit][:questions] = [
389
+        @checker.options['hit']['questions'] = [
390 390
           {
391
-            :type => "selection",
392
-            :key => "rating",
393
-            :name => "Rating",
394
-            :required => "true",
395
-            :question => "Please select a rating:",
396
-            :selections =>
391
+            'type' => "selection",
392
+            'key' => "rating",
393
+            'name' => "Rating",
394
+            'required' => "true",
395
+            'question' => "Please select a rating:",
396
+            'selections' =>
397 397
               [
398
-                { :key => "1", :text => "One" },
399
-                { :key => "2", :text => "Two" },
400
-                { :key => "3", :text => "Three" },
401
-                { :key => "4", :text => "Four" },
402
-                { :key => "5.1", :text => "Five Point One" }
398
+                { 'key' => "1", 'text' => "One" },
399
+                { 'key' => "2", 'text' => "Two" },
400
+                { 'key' => "3", 'text' => "Three" },
401
+                { 'key' => "4", 'text' => "Four" },
402
+                { 'key' => "5.1", 'text' => "Five Point One" }
403 403
               ]
404 404
           }
405 405
         ]
@@ -420,7 +420,7 @@ describe Agents::HumanTaskAgent do
420 420
 
421 421
         assignments.all? {|a| a.approved == true }.should be_true
422 422
 
423
-        @checker.events.last.payload[:answers].should == [
423
+        @checker.events.last.payload['answers'].should == [
424 424
           { 'rating' => "1" },
425 425
           { 'rating' => "3" },
426 426
           { 'rating' => "5.1" },
@@ -428,11 +428,11 @@ describe Agents::HumanTaskAgent do
428 428
           { 'rating' => "2" }
429 429
         ]
430 430
 
431
-        @checker.events.last.payload[:counts].should == { 'rating' => { "1" => 1, "2" => 2, "3" => 1, "4" => 0, "5.1" => 1 } }
432
-        @checker.events.last.payload[:majority_answer].should == { 'rating' => "2" }
433
-        @checker.events.last.payload[:average_answer].should == { 'rating' => (1 + 2 + 2 + 3 + 5.1) / 5.0 }
431
+        @checker.events.last.payload['counts'].should == { 'rating' => { "1" => 1, "2" => 2, "3" => 1, "4" => 0, "5.1" => 1 } }
432
+        @checker.events.last.payload['majority_answer'].should == { 'rating' => "2" }
433
+        @checker.events.last.payload['average_answer'].should == { 'rating' => (1 + 2 + 2 + 3 + 5.1) / 5.0 }
434 434
 
435
-        @checker.memory[:hits].should == {}
435
+        @checker.memory['hits'].should == {}
436 436
       end
437 437
     end
438 438
   end

+ 29 - 29
spec/models/agents/peak_detector_agent_spec.rb

@@ -3,12 +3,12 @@ require 'spec_helper'
3 3
 describe Agents::PeakDetectorAgent do
4 4
   before do
5 5
     @valid_params = {
6
-        :name => "my peak detector agent",
7
-        :options => {
8
-            :expected_receive_period_in_days => "2",
9
-            :group_by_path => "filter",
10
-            :value_path => "count",
11
-            :message => "A peak was found"
6
+        'name' => "my peak detector agent",
7
+        'options' => {
8
+          'expected_receive_period_in_days' => "2",
9
+          'group_by_path' => "filter",
10
+          'value_path' => "count",
11
+          'message' => "A peak was found"
12 12
         }
13 13
     }
14 14
 
@@ -19,54 +19,54 @@ describe Agents::PeakDetectorAgent do
19 19
 
20 20
   describe "#receive" do
21 21
     it "tracks and groups by the group_by_path" do
22
-      events = build_events(:keys => [:count, :filter],
22
+      events = build_events(:keys => ['count', 'filter'],
23 23
                             :values => [[1, "something"], [2, "something"], [3, "else"]])
24 24
       @agent.receive events
25
-      @agent.memory[:data][:something].map(&:first).should == [1, 2]
26
-      @agent.memory[:data][:something].last.last.should be_within(10).of((100 - 1).hours.ago.to_i)
27
-      @agent.memory[:data][:else].first.first.should == 3
28
-      @agent.memory[:data][:else].first.last.should be_within(10).of((100 - 2).hours.ago.to_i)
25
+      @agent.memory['data']['something'].map(&:first).should == [1, 2]
26
+      @agent.memory['data']['something'].last.last.should be_within(10).of((100 - 1).hours.ago.to_i)
27
+      @agent.memory['data']['else'].first.first.should == 3
28
+      @agent.memory['data']['else'].first.last.should be_within(10).of((100 - 2).hours.ago.to_i)
29 29
     end
30 30
 
31 31
     it "works without a group_by_path as well" do
32
-      @agent.options[:group_by_path] = ""
33
-      events = build_events(:keys => [:count], :values => [[1], [2]])
32
+      @agent.options['group_by_path'] = ""
33
+      events = build_events(:keys => ['count'], :values => [[1], [2]])
34 34
       @agent.receive events
35
-      @agent.memory[:data][:no_group].map(&:first).should == [1, 2]
35
+      @agent.memory['data']['no_group'].map(&:first).should == [1, 2]
36 36
     end
37 37
 
38 38
     it "keeps a rolling window of data" do
39
-      @agent.options[:window_duration_in_days] = 5/24.0
40
-      @agent.receive build_events(:keys => [:count],
39
+      @agent.options['window_duration_in_days'] = 5/24.0
40
+      @agent.receive build_events(:keys => ['count'],
41 41
                                   :values => [1, 2, 3, 4, 5, 6, 7, 8].map {|i| [i]},
42
-                                  :pattern => { :filter => "something" })
43
-      @agent.memory[:data][:something].map(&:first).should == [4, 5, 6, 7, 8]
42
+                                  :pattern => { 'filter' => "something" })
43
+      @agent.memory['data']['something'].map(&:first).should == [4, 5, 6, 7, 8]
44 44
     end
45 45
 
46 46
     it "finds peaks" do
47
-      build_events(:keys => [:count],
47
+      build_events(:keys => ['count'],
48 48
                    :values => [5, 6,
49 49
                                4, 5,
50 50
                                4, 5,
51 51
                                15, 11, # peak
52 52
                                8, 50, # ignored because it's too close to the first peak
53 53
                                4, 5].map {|i| [i]},
54
-                   :pattern => { :filter => "something" }).each.with_index do |event, index|
54
+                   :pattern => { 'filter' => "something" }).each.with_index do |event, index|
55 55
         lambda {
56 56
           @agent.receive([event])
57 57
         }.should change { @agent.events.count }.by( index == 6 ? 1 : 0 )
58 58
       end
59 59
 
60
-      @agent.events.last.payload[:peak].should == 15.0
61
-      @agent.memory[:peaks][:something].length.should == 1
60
+      @agent.events.last.payload['peak'].should == 15.0
61
+      @agent.memory['peaks']['something'].length.should == 1
62 62
     end
63 63
 
64 64
     it "keeps a rolling window of peaks" do
65
-      @agent.options[:min_peak_spacing_in_days] = 1/24.0
66
-      @agent.receive build_events(:keys => [:count],
65
+      @agent.options['min_peak_spacing_in_days'] = 1/24.0
66
+      @agent.receive build_events(:keys => ['count'],
67 67
                                   :values => [1, 1, 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 10, 1].map {|i| [i]},
68
-                                  :pattern => { :filter => "something" })
69
-      @agent.memory[:peaks][:something].length.should == 2
68
+                                  :pattern => { 'filter' => "something" })
69
+      @agent.memory['peaks']['something'].length.should == 2
70 70
     end
71 71
   end
72 72
 
@@ -76,17 +76,17 @@ describe Agents::PeakDetectorAgent do
76 76
     end
77 77
 
78 78
     it "should validate presence of message" do
79
-      @agent.options[:message] = nil
79
+      @agent.options['message'] = nil
80 80
       @agent.should_not be_valid
81 81
     end
82 82
 
83 83
     it "should validate presence of expected_receive_period_in_days" do
84
-      @agent.options[:expected_receive_period_in_days] = ""
84
+      @agent.options['expected_receive_period_in_days'] = ""
85 85
       @agent.should_not be_valid
86 86
     end
87 87
 
88 88
     it "should validate presence of value_path" do
89
-      @agent.options[:value_path] = ""
89
+      @agent.options['value_path'] = ""
90 90
       @agent.should_not be_valid
91 91
     end
92 92
   end

+ 53 - 53
spec/models/agents/trigger_agent_spec.rb

@@ -3,16 +3,16 @@ require 'spec_helper'
3 3
 describe Agents::TriggerAgent do
4 4
   before do
5 5
     @valid_params = {
6
-        :name => "my trigger agent",
7
-        :options => {
8
-            :expected_receive_period_in_days => 2,
9
-            :rules => [{
10
-                           :type => "regex",
11
-                           'value' => "a\\db",
12
-                           :path => "foo.bar.baz",
13
-                       }],
14
-            :message => "I saw '<foo.bar.baz>' from <name>"
15
-        }
6
+      'name' => "my trigger agent",
7
+      'options' => {
8
+        'expected_receive_period_in_days' => 2,
9
+        'rules' => [{
10
+                      'type' => "regex",
11
+                      'value' => "a\\db",
12
+                      'path' => "foo.bar.baz",
13
+                    }],
14
+        'message' => "I saw '<foo.bar.baz>' from <name>"
15
+      }
16 16
     }
17 17
 
18 18
     @checker = Agents::TriggerAgent.new(@valid_params)
@@ -21,8 +21,8 @@ describe Agents::TriggerAgent do
21 21
 
22 22
     @event = Event.new
23 23
     @event.agent = agents(:bob_rain_notifier_agent)
24
-    @event.payload = { :foo => { "bar" => { :baz => "a2b" }},
25
-                       :name => "Joe" }
24
+    @event.payload = { 'foo' => { "bar" => { 'baz' => "a2b" }},
25
+                       'name' => "Joe" }
26 26
   end
27 27
 
28 28
   describe "validation" do
@@ -31,22 +31,22 @@ describe Agents::TriggerAgent do
31 31
     end
32 32
 
33 33
     it "should validate presence of options" do
34
-      @checker.options[:message] = nil
34
+      @checker.options['message'] = nil
35 35
       @checker.should_not be_valid
36 36
     end
37 37
 
38 38
     it "should validate the three fields in each rule" do
39
-      @checker.options[:rules] << { :path => "foo", :type => "fake", :value => "6" }
39
+      @checker.options['rules'] << { 'path' => "foo", 'type' => "fake", 'value' => "6" }
40 40
       @checker.should_not be_valid
41
-      @checker.options[:rules].last[:type] = "field>=value"
41
+      @checker.options['rules'].last['type'] = "field>=value"
42 42
       @checker.should be_valid
43
-      @checker.options[:rules].last.delete(:value)
43
+      @checker.options['rules'].last.delete('value')
44 44
       @checker.should_not be_valid
45 45
     end
46 46
   end
47 47
 
48 48
   describe "#working?" do
49
-    it "checks to see if the Agent has received any events in the last :expected_receive_period_in_days days" do
49
+    it "checks to see if the Agent has received any events in the last 'expected_receive_period_in_days' days" do
50 50
       @event.save!
51 51
 
52 52
       @checker.should_not be_working # no events have ever been received
@@ -60,30 +60,30 @@ describe Agents::TriggerAgent do
60 60
 
61 61
   describe "#receive" do
62 62
     it "handles regex" do
63
-      @event.payload[:foo]["bar"][:baz] = "a222b"
63
+      @event.payload['foo']['bar']['baz'] = "a222b"
64 64
       lambda {
65 65
         @checker.receive([@event])
66 66
       }.should_not change { Event.count }
67 67
 
68
-      @event.payload[:foo]["bar"][:baz] = "a2b"
68
+      @event.payload['foo']['bar']['baz'] = "a2b"
69 69
       lambda {
70 70
         @checker.receive([@event])
71 71
       }.should change { Event.count }.by(1)
72 72
     end
73 73
 
74 74
     it "handles negated regex" do
75
-      @event.payload[:foo]["bar"][:baz] = "a2b"
76
-      @checker.options[:rules][0] = {
77
-                                      :type => "!regex",
78
-                                      :value => "a\\db",
79
-                                      :path => "foo.bar.baz",
80
-                                    }
75
+      @event.payload['foo']['bar']['baz'] = "a2b"
76
+      @checker.options['rules'][0] = {
77
+        'type' => "!regex",
78
+        'value' => "a\\db",
79
+        'path' => "foo.bar.baz",
80
+      }
81 81
 
82 82
       lambda {
83 83
         @checker.receive([@event])
84 84
       }.should_not change { Event.count }
85 85
 
86
-      @event.payload[:foo]["bar"][:baz] = "a22b"
86
+      @event.payload['foo']['bar']['baz'] = "a22b"
87 87
       lambda {
88 88
         @checker.receive([@event])
89 89
       }.should change { Event.count }.by(1)
@@ -91,49 +91,49 @@ describe Agents::TriggerAgent do
91 91
 
92 92
     it "puts can extract values into the message based on paths" do
93 93
       @checker.receive([@event])
94
-      Event.last.payload[:message].should == "I saw 'a2b' from Joe"
94
+      Event.last.payload['message'].should == "I saw 'a2b' from Joe"
95 95
     end
96 96
 
97 97
     it "handles numerical comparisons" do
98
-      @event.payload[:foo]["bar"][:baz] = "5"
99
-      @checker.options[:rules].first[:value] = 6
100
-      @checker.options[:rules].first[:type] = "field<value"
98
+      @event.payload['foo']['bar']['baz'] = "5"
99
+      @checker.options['rules'].first['value'] = 6
100
+      @checker.options['rules'].first['type'] = "field<value"
101 101
 
102 102
       lambda {
103 103
         @checker.receive([@event])
104 104
       }.should change { Event.count }.by(1)
105 105
 
106
-      @checker.options[:rules].first[:value] = 3
106
+      @checker.options['rules'].first['value'] = 3
107 107
       lambda {
108 108
         @checker.receive([@event])
109 109
       }.should_not change { Event.count }
110 110
     end
111 111
 
112 112
     it "handles exact comparisons" do
113
-      @event.payload[:foo]["bar"][:baz] = "hello world"
114
-      @checker.options[:rules].first[:type] = "field==value"
113
+      @event.payload['foo']['bar']['baz'] = "hello world"
114
+      @checker.options['rules'].first['type'] = "field==value"
115 115
 
116
-      @checker.options[:rules].first[:value] = "hello there"
116
+      @checker.options['rules'].first['value'] = "hello there"
117 117
       lambda {
118 118
         @checker.receive([@event])
119 119
       }.should_not change { Event.count }
120 120
 
121
-      @checker.options[:rules].first[:value] = "hello world"
121
+      @checker.options['rules'].first['value'] = "hello world"
122 122
       lambda {
123 123
         @checker.receive([@event])
124 124
       }.should change { Event.count }.by(1)
125 125
     end
126 126
 
127 127
     it "handles negated comparisons" do
128
-      @event.payload[:foo]["bar"][:baz] = "hello world"
129
-      @checker.options[:rules].first[:type] = "field!=value"
130
-      @checker.options[:rules].first[:value] = "hello world"
128
+      @event.payload['foo']['bar']['baz'] = "hello world"
129
+      @checker.options['rules'].first['type'] = "field!=value"
130
+      @checker.options['rules'].first['value'] = "hello world"
131 131
 
132 132
       lambda {
133 133
         @checker.receive([@event])
134 134
       }.should_not change { Event.count }
135 135
 
136
-      @checker.options[:rules].first[:value] = "hello there"
136
+      @checker.options['rules'].first['value'] = "hello there"
137 137
 
138 138
       lambda {
139 139
         @checker.receive([@event])
@@ -141,20 +141,20 @@ describe Agents::TriggerAgent do
141 141
     end
142 142
 
143 143
     it "does fine without dots in the path" do
144
-      @event.payload = { :hello => "world" }
145
-      @checker.options[:rules].first[:type] = "field==value"
146
-      @checker.options[:rules].first[:path] = "hello"
147
-      @checker.options[:rules].first[:value] = "world"
144
+      @event.payload = { 'hello' => "world" }
145
+      @checker.options['rules'].first['type'] = "field==value"
146
+      @checker.options['rules'].first['path'] = "hello"
147
+      @checker.options['rules'].first['value'] = "world"
148 148
       lambda {
149 149
         @checker.receive([@event])
150 150
       }.should change { Event.count }.by(1)
151 151
 
152
-      @checker.options[:rules].first[:path] = "foo"
152
+      @checker.options['rules'].first['path'] = "foo"
153 153
       lambda {
154 154
         @checker.receive([@event])
155 155
       }.should_not change { Event.count }
156 156
 
157
-      @checker.options[:rules].first[:value] = "hi"
157
+      @checker.options['rules'].first['value'] = "hi"
158 158
       lambda {
159 159
         @checker.receive([@event])
160 160
       }.should_not change { Event.count }
@@ -163,11 +163,11 @@ describe Agents::TriggerAgent do
163 163
     it "handles multiple events" do
164 164
       event2 = Event.new
165 165
       event2.agent = agents(:bob_weather_agent)
166
-      event2.payload = { :foo => { "bar" => { :baz => "a2b" }}}
166
+      event2.payload = { 'foo' => { 'bar' => { 'baz' => "a2b" }}}
167 167
 
168 168
       event3 = Event.new
169 169
       event3.agent = agents(:bob_weather_agent)
170
-      event3.payload = { :foo => { "bar" => { :baz => "a222b" }}}
170
+      event3.payload = { 'foo' => { 'bar' => { 'baz' => "a222b" }}}
171 171
 
172 172
       lambda {
173 173
         @checker.receive([@event, event2, event3])
@@ -175,19 +175,19 @@ describe Agents::TriggerAgent do
175 175
     end
176 176
 
177 177
     it "handles ANDing rules together" do
178
-      @checker.options[:rules] << {
179
-          :type => "field>=value",
180
-          :value => "4",
181
-          :path => "foo.bing"
178
+      @checker.options['rules'] << {
179
+        'type' => "field>=value",
180
+        'value' => "4",
181
+        'path' => "foo.bing"
182 182
       }
183 183
 
184
-      @event.payload[:foo]["bing"] = "5"
184
+      @event.payload['foo']["bing"] = "5"
185 185
 
186 186
       lambda {
187 187
         @checker.receive([@event])
188 188
       }.should change { Event.count }.by(1)
189 189
 
190
-      @checker.options[:rules].last[:value] = 6
190
+      @checker.options['rules'].last['value'] = 6
191 191
       lambda {
192 192
         @checker.receive([@event])
193 193
       }.should_not change { Event.count }